我不明白为什么会这样。 pReallyABase是一个下载的shared_pointer<派生>它指向基类实例。
我理解为什么编译器允许我调用pReallyABase-> onlyForDerived(),因为我将它定义为派生类指针,但是当我尝试使用派生类函数调用派生类函数时,为什么不会出现运行时错误指针?
class Base {
public:
virtual string whatAmI() {
return "I am a Base";
}
};
class Derived : public Base {
public:
virtual string whatAmI() {
return "I am a Derived";
}
string onlyForDerived() {
return "I can do Derived things";
}
};
int main(int argc, char *argv[]) {
shared_ptr<Base> pBase = shared_ptr<Base>(new Base);
shared_ptr<Derived> pReallyABase = static_pointer_cast<Derived>(pBase);
cout << pReallyABase->whatAmI() << endl;
cout << pReallyABase->onlyForDerived() << endl; //Why does this work?
return 0;
}
I am a Base
I can do Derived things
答案 0 :(得分:2)
这是关于如何在C ++中调用成员函数(非静态和非虚拟),本书&#34; Inside C ++对象模型&#34;有一个解释:
一个C ++设计标准是非静态成员函数至少必须为 作为类似的非成员函数有效。不应该有额外的开销 用于选择成员函数实例。这是通过内部转换实现的 将成员实例放入等效的非成员实例中。经过这些转变 每个调用也必须进行转换:例如:
obj.magnitude();
变为
magnitude_7Point3dFv(&obj);
和
ptr->magnitude();
变为
magnitude_7Point3dFv(ptr);
因此,如上例所示,函数onlyForDerived不使用Derived类的任何成员变量,因此它可以工作。但这是一种未定义的行为,我们不应该依赖它。
答案 1 :(得分:2)
您通过将Base
对象视为Derived
来自动获取未定义的行为,因此您认为任何行为都是合法的。
在这种情况下,由于编译器“知道”派生指针的静态类型是Derived
,它能够调用函数,即使这样做是不合法的。
它不会引发运行时错误,因为它没有(undefined未定义)。也就是说,如果函数是虚拟的,它可能会在大多数实现中崩溃,并且如果派生类具有派生函数引用它的数据可能会崩溃或产生意外输出。