![](/img/trans.png)
[英]C++: call (derived's) member function on base pointer of a different derived class's object
[英]Why cannot reach derived class's member function using a base class pointer in C++? What's the design idea of it?
我认为,使用基类指针可以达到派生类的内容。 也许我认为这就像火车一样,只要找到它的头,我就可以到达所有公共的地方。
但是,当我尝试执行此类操作时,出现一个错误,即基类无法找到派生类的成员函数。 尽管我使用基类指针变量来记录派生类的地址,但我认为它也可以达到训练头的派生类成员函数。 事实证明事实并非如此。 所以我想知道它的设计思想是什么。 为什么它的设计不像Python可以做到? 这种设计思想的优点是什么?
示意图:
演示代码:
#include <iostream>
using namespace std;
class B{
public:
void helloB(){
cout << "hello B" << endl;
}
};
class C:public B{
public:
void helloC(){
cout << "hello C" << endl;
}
};
class A{
public:
B* t;
void helloA(){
t->helloC();
}
};
int main(){
A a;
C c;
a.t = &c;
a.helloA();
}
C ++是静态类型的语言。 也就是说,它在编译时而不是在运行时进行类型检查。
在编译时,编译器无法知道t
(它知道具有B*
类型)具有helloC
方法。 该语言试图通过调用未定义的行为(如果该方法不存在)来阻止您脚下弹。
相反,Python是一种动态语言,没有静态类型检查。
在静态检查与动态检查之间存在权衡 。 动态检查更灵活,但通常意味着您无法捕获某些错误,除非您在运行时使用所有代码路径。 静态检查有助于及早发现错误,并允许进行更好的优化(例如,更快)的代码。 例如,当调用A::helloA
,如果B::helloC
存在,则程序无需首先检查t
是否具有helloC
方法; 在编译时就已经证明了这一点。
C ++是静态类型的,因为它的目标受众是想要优化速度的开发人员。
为了在C ++中避免这种情况,您必须将接口推入基类并使其成为虚拟方法,或者执行向下转换以强制将指向基类的指针(或引用)视为对派生类的指针/引用。 。 在这种情况下,您可以使用static_cast
:
void helloA(){
static_cast<C*>(t)->helloC();
}
它告诉编译器您绝对可以肯定 t
实际上是C*
。 这将不会增加运行时开销,但是也不会增加运行时开销,也就意味着没有运行时检查t
是否实际上是C*
。
向下转换的一种更通用的方法是使用dynamic_cast
:
void helloA(){
C* c = dynamic_cast<C*>(t);
if (c != null) {
c->helloC();
}
}
这将在运行时检查t
是否实际上是C*
。 当然,运行时检查会产生运行时成本。
好的,编译器除了是类B的实例外,对有关对象一无所知。您可以从B派生一些其他类,并且它们将适合于类B可以适合的任何地方。 考虑一下:B类是更一般的东西(比方说是动物),而C类或从B派生的任何其他类是某种动物。 假设是狗或鸟。 假设所有动物都可以发出声音,但只有鸟类可以产卵。 现在您可以拥有一组动物,并告诉它们全部发出声音,但是您不能告诉所有它们都下蛋。 在此抽象级别上,编译器没有下蛋的想法。 在您的代码中,编译器无法确定您是在谈论类C的实例。
我的朋友,您需要阅读一些有关c ++继承的知识,或者至少要了解c ++和python之间的继承差异。
从您的示例中,您似乎在问狗说喵喵:D
C类是从B类继承而来的,因此不能从B类的对象调用C类的helloC方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.