繁体   English   中英

C ++如何在不使用static_cast或dynamic_cast的情况下从基类指针访问派生类成员?

[英]C++ How to access derived class member from base class pointer without using a static_cast or dynamic_cast?

我看到了以下问题 ,我问自己是否有更好的方法来解决此问题,因此不需要强制转换。 考虑以下代码:

#include <iostream>

class Base
{
    public:
        virtual ~Base() {}
};

class Derived : public Base
{
    protected:
        int someVar = 2;

    public:
        int getSomeVar () {return this->someVar;}   
};


int main()
{
    Base    B = Base(); 
    Derived D = Derived();

    Base *PointerToDerived  = &D;
    Base *PointerToBase     = &B;

    std::cout << dynamic_cast<Derived*>(PointerToDerived)->getSomeVar() << "\n"; //this will work
    std::cout << dynamic_cast<Derived*>(PointerToBase)->getSomeVar() << "\n"; //this will create a runtime error

    return 0;

}

有没有更好的方法来设计它,因此不需要强制转换并且可以避免类似的运行时错误?

是的,您无需任何强制转换即可做到:

class Base
{
    public:
        virtual ~Base() {}
        virtual int getSomeVar () = 0;
};

class Derived : public Base
{
    protected:
        int someVar = 2;

    public:
        virtual int getSomeVar () {return this->someVar;}   
};

int main()
{
//    Base    B = Base(); // will not compile, therefore you're safe
    Derived D = Derived();

    Base *PointerToDerived  = &D;
//    Base *PointerToBase     = &B;

    std::cout << PointerToDerived->getSomeVar() << "\n"; // no cast needed

    return 0;

}

如果您还希望能够构造Base类,则可以提供该方法的“默认”实现,而不是将其纯虚拟化。

(同样,在这种情况下,方法应该是const

如果我对您的理解正确,则希望在基类上调用派生类的函数。 这没有很好的定义。

相反,您可以在基类中声明一个虚函数,该虚函数将被派生类覆盖。 请参阅为什么我们需要C ++中的虚函数? Wikipedia:虚拟功能了解更多详细信息。

您可以在此处应用一个不错的“功能性”可重用技巧:

template<typename Interface, typename Class, typename Function>
void with(Class * anObject, Function f) {
   if (auto * i = dynamic_cast<Interface*>(anObject))
     f(*i);
}

用法:

with<Derived>(PointerToBase, [](auto &derived) {
  std::cout << derived.getSomeVar() << "\n"; // wont be called
}
with<Derived>(PointerToDerived, [](auto &derived) {
  std::cout << derived.getSomeVar() << "\n"; // will be called
}

http://cpp.sh/9vzis上的示例

避免运行时错误。

Derived* derived = dynamic_cast<Derived*>(PointerToBase);
if (derived != NULL) {
    std::cout << ->getSomeVar() << "\n"; 
}

当然,您不能将Base DerivedDerived

访问者模式使用双调度,以允许您使用特定于类的成员函数和成员变量(与成员函数/可通过层次结构使用的变量相对)。

为了实现访问者模式,你需要一个访问者访问层级(在你的例子是Base和来自类Base )。 以您的示例为例,它将给出以下内容:

class Base
{
    public:
        virtual ~Base() {}
        virtual void visit(Visitor) = 0;
};

class Derived : public Base
{
    protected:
        int someVar = 2;

    public:
        int getSomeVar () {return this->someVar;}
        void visit(Visitor& v) {
            v.visit(this);
         }
};
class Visitor {
    public:
         void visit(Derived& d) {
              bar(d.someVar);
         }
};

访问者背后的想法是, thisDerived知道它是真实的类型,而一个多态变量(一个Base&Base* )没有。 压倒一切的Base::visit让你调用visit谁做调度向右Visitor::visit

如果不重写Base::visit ,在调用它时Base& (或Base* ),它会调用该函数Base的对象(所以this将是类型的Base* )。 这就是为什么示例Base::visit是抽象的,否则这样做只会使错误更有可能发生(例如忘记覆盖visit )。

Base层次结构中添加新类型时(例如Derived2类),您将需要添加两个函数: Derived2::visitVisitor::visit(Derived2) (或Visitor::visit(Derived2&) )。

编辑

现场例子

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM