最近有关SO的问题让我想到了以下几点。
请考虑以下代码:
class Base{
public:
void print() { cout<<"In Base"<<endl;}
};
class Derived: public Base{
public:
void print() { cout<<"In Derived"<<endl;}
};
int main(void)
{
Base *bp;
Derived ob;
bp = &ob;
(*bp).print(); // prints: In Base
ob.print(); // print: In Derived
return 0;
}
为什么(*bp),print()
的行为与ob.print()
不相似。
我认为(* bp)应该返回对象ob
,因为bp
被引用到对象ob
,当我们使用*
运算符取消引用时我们得到该地址的值,ob
对象存储在bp
中的地址中。所以第一个函数调用应该与发送函数调用相同。
请澄清这个概念。
答案 0 :(得分:4)
你正在做的事情被称为“方法隐藏”,是一种代码味道,一种坏习惯,一种不应该做的事情。
您应该在基类中将打印方法定义为virtual
。
(并且不要忘记virtual
类中的Base
析构函数。)
class Base{
public:
virtual void print() { cout<<"In Base"<<endl;}
virtual ~Base(){}
};
class Derived: public Base{
public:
void print() { cout<<"In Derived"<<endl;}
};
答案 1 :(得分:2)
您是否错过宣布功能print()
virtual
? ;)
class Base{
public:
virtual void print() { cout<<"In Base"<<endl;}
};
答案 2 :(得分:1)
始终决定是基于指针类型而不是指针内容。前一个绑定称为Early Binding
,后者是Late Binding
。
如果我们重新定义以virtual
关键字开头的方法print(),则结果将符合要求。
class Base
{
public:
virtual void print()
{
cout<<"In Base"<<endl;
}
};
class Derived: public Base
{
public:
void print()
{
cout<<"In Derived"<<endl;
}
};
当使用指针或对基类的引用引用派生类对象时,可以为该对象调用虚函数并执行派生类的函数版本。虚函数确保为对象调用正确的函数,而不管用于进行函数调用的表达式。
使用指针或引用调用函数时,以下规则适用:
您可以查看虚拟表和虚拟函数的概念以获取更多详细信息
答案 3 :(得分:0)
编译器使用静态类型的变量。变量bp具有静态类型Base *,因此编译器检查Base的类定义中是否存在这样的函数并调用它。您想要实现的效果可以使用虚函数完成。在这种情况下,编译器使用指向虚函数的指针表来调用函数。在这种情况下,由于bp具有动态类型Derived *,因此该表将包含指向Derived类中定义的虚函数的指针。您需要做的就是将函数说明符virtual添加到类Base
中的函数定义中class Base{
public:
virtual void print() { cout<<"In Base"<<endl;}
virtual ~Base() = default};
答案 4 :(得分:0)
Base
可能有很多派生类。在(*bp).print()
时刻,你不知道它们中的哪一个(如果有的话)是真正的基础对象类。因此,所有编译器都可以调用Base::print
。
但是如果你包含一些关于实际类(vtable
)的信息,那么就可以按照你想要的方式进行(使用virtual
函数,如其他人所建议的那样)。