通过基类指针取消引用

时间:2013-12-31 08:53:15

标签: c++

最近有关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中的地址中。所以第一个函数调用应该与发送函数调用相同。

请澄清这个概念。

5 个答案:

答案 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函数,如其他人所建议的那样)。