我不明白为什么这样行得通。pReallyABase是一个向下转换的shared_pointer< Derived >,它指向一个基类实例。
我理解为什么编译器允许我调用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发布于 2014-07-31 04:14:18
关于如何在C++中调用成员函数(非静态和非虚的),“C++对象模型内部”一书对此进行了解释:
一个C++设计标准是,非静态成员函数至少必须与其类似的非成员函数一样有效。选择成员函数实例不应该有额外的开销。这是通过在内部将成员实例转换为等效的非成员实例来实现的。在这些转换之后,它的每个调用也必须进行转换:例如:
obj.magnitude();变成了
magnitude_7Point3dFv(&obj);和
ptr->magnitude();变成了
magnitude_7Point3dFv(ptr);因此,如上面的示例所示,函数onlyForDerived没有使用派生类的任何成员变量,因此它是有效的。但这是一种未定义的行为,我们不应该依赖它。
发布于 2014-07-31 04:19:33
通过将Base对象视为Derived,您将自动获得未定义的行为,因此您看到的任何行为都是合法的。
在这种情况下,因为编译器“知道”派生指针的静态类型是Derived,所以它能够调用函数,即使这样做是不合法的。
它不会引发运行时错误,因为它不需要引发运行时错误(未定义就是未定义)。也就是说,如果函数是虚的,它可能会在大多数实现中崩溃,如果派生类具有派生函数引用的数据,则可能会崩溃或生成意外输出。
https://stackoverflow.com/questions/25045656
复制相似问题