C ++如何在不使用static_cast或dynamic_cast的情况下从基类指针访问派生类成员?
我看到了以下问题,我问自己,是否有更好的方法来解决此问题,因此不需要强制转换.考虑以下代码:
I saw the following question and I asked myself if there is a better way to address this problem, so there is no need for a cast. Consider the following code:
#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;
}
是否有更好的设计方法,因此不需要强制转换,并且可以避免类似的运行时错误?
Is there a better way to design this, so no cast is needed and runtime errors like this can be avoided?
访问者模式使用double dispatch允许您使用特定于类的成员函数和成员变量(与成员函数/可在层次结构中使用的变量相对).
The visitor pattern use double dispatch to allow you to use class-specific member function and member variable (opposed to member function/variable available through the hierarchy).
要实现访客模式,您需要一个 visitor 和一个 visited 的层次结构(在您的示例中,它是 Base
以及从基本
).以您的示例为例,它会给出类似的信息:
To implement the visitor pattern, you need a visitor and a hierarchy of visited (in your example it's Base
and the classes derived from Base
).
With your example it would give something like that:
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);
}
};
访问者背后的想法是, this
的 Derived
知道它是实型,而一个多态变量( Base&
或基本*
)不可以.通过覆盖 Base :: visit
,您可以调用 visit
,后者将向右侧的 Visitor :: visit
进行调度.
The idea behind the visitor is that this
of Derived
know it's real type while a polymorphic variable (a Base&
or Base*
) don't. OverridingBase::visit
allow you to call the visit
who will do the dispatch to the right Visitor::visit
.
如果您不覆盖 Base :: visit
,则在 Base&
(或 Base *
)上调用它时,它将调用 Base
对象上的函数(因此 this
的类型为 Base *
).这就是为什么示例 Base :: visit
是抽象的,否则这样做只会使错误更有可能发生(例如忘记覆盖 visit
).
If you don't override Base::visit
, when calling it on a Base&
(or Base*
) it will call the function on a Base
object (so this
will be of type Base*
). That's why in the example Base::visit
is abstract, doing otherwise will only make error more likely to happen (like forgetting to override visit
).
在 Base
层次结构中添加新类型时(例如 Derived2
类),您将需要添加两个函数: Derived2 :: visit
和 Visitor :: visit(Derived2)
(或 Visitor :: visit(Derived2&)
).
When adding a new type in the Base
hierarchy (for example a Derived2
class), you will need to add two functions: Derived2::visit
and Visitor::visit(Derived2)
(or Visitor::visit(Derived2&)
).
编辑