【问题标题】:Why can't a 'Base Class object' call it's own virtual function? C++为什么“基类对象”不能调用它自己的虚函数? C++
【发布时间】:2014-09-02 13:11:53
【问题描述】:

我已经阅读了 C++ 中的虚函数,并了解了它们如何让程序员使用基类的指针访问派生类的成员函数。 (又名多态)。

一直困扰我的问题是:

  1. 为什么要在基类中声明一个同名的函数,如果最后必须声明为虚拟函数? (注意:我需要关于虚函数的多态性方面的答案)
  2. 在下面的代码中,如果使用基类指针(第 22 行)调用“virtual display()”,则会显示错误。为什么 C++ 中的虚函数如此严格 w.r.t.没有被基类指针调用?

.

#include <iostream>
using namespace std;

class B
{
    public:
       void virtual display()
         { cout<<"Inside base class.\n"; }

};

class D : public B
{
    public:
       void display()
         { cout<<"Inside derived class.\n"; }
};

int main()
{
    B *b;
    D d;

//Line-22    b->display();  Why can't 'b' call it's own display()?

    b = &d; 
    b->display();

    system("pause");
    return 0;
}

输出:

在派生类中。

【问题讨论】:

  • 你可以在调用 display 之前调用它的基类来做到这一点:b-&gt;B::display()
  • @CollioTV 谢谢。它有效:)
  • @CollioTV:尽管使用无效指针执行此操作仍然是非法的(即使在此示例中,它可能看起来是偶然的)。

标签: c++ polymorphism virtual-functions


【解决方案1】:

b 是指针而不是对象。最初它没有指向任何东西(因此通过它间接是一个错误);在b = &amp;d之后,它指向一个D对象,所以用它调用虚函数会调用D的覆盖。

定义了虚拟调度机制,以便根据指针指向的实际对象的类型来选择函数,而不是指针的声明类型。因此,如果它指向一个B 对象,那么它将调用B::display;这里,它指向一个D 对象,所以它调用D::display

为什么要在基类中声明一个同名的函数,如果最终必须声明为虚拟函数?

它需要在基类中声明,以便在使用指向基类的指针时,编译器知道它存在。通过指针调用函数是调用基类版本,还是被派生类覆盖的版本,取决于对象的类型。

在下面的代码中,如果使用基类指针(第 22 行)调用 virtual display(),则会显示错误。

那是因为它不指向任何东西,所以使用它是一个错误。如果它指向一个B 对象,那么它将调用B 中声明的函数。

B b_obj;
b = &b_obj;
b->display();   // "Inside base class"

为什么 C++ 中的虚函数如此死板。没有被基类指针调用?

他们不是;这是通常的称呼方式。但是指针必须指向一个有效的对象,虚拟调度才能工作。

【讨论】:

  • 感谢您在一行中解释“虚拟调度机制”。
【解决方案2】:

我承认我不太明白你的问题 #1。在基类中声明虚函数允许派生类覆盖该实现。

这有很多用途(只需搜索多态性、Liskov 替换等)。作为一个简单(和人为)的例子,考虑一下:

struct File
{
  virtual void open() { some_code; }
  virtual void close() { some_code; }

  static std::unique_ptr<File> create();
};

struct DbgFile : File
{
  virtual void open() { std::clog << "Opening"; File::open(); }
  virtual void open() { std::clog << "Closing"; File::close(); }
};

std::unique_ptr<File> File::create()
{
#ifdef NDEBUG
  return { new File };
#else
  return { new DbgFile };
#endif
}

int main()
{
  auto f = File::create();
  f->open();
  f->close();
}

上面的main() 使用File 接口,但在调试版本中,它实际上会使用DbgFile 类型的对象,该对象会记录发生在其上的所有操作。


关于您的问题 #2,您的代码中的问题是 b 没有指向任何地方。如果你这样做,它会工作得很好:

int main()
{
    B *b;
    B bb;
    D d;

    b = &bb;
    b->display();  // Outputs "Inside base class."

    b = &d; 
    b->display();  // Outputs "Inside derived class."

    // In addition, you can explicitly suppress dynamic dispatch:
    b->B::display();  // Outputs "Inside base class."

    return 0;
}

【讨论】:

  • 通过您的上次更新,我可以轻松地将虚函数和多态性关联起来。发送。
【解决方案3】:

为什么要在基类中声明一个同名的函数,如果最终必须声明为虚拟函数? (注意:我需要关于虚函数的多态性方面的答案)

这是必要的,因为基类必须知道它需要在运行时调用哪个函数定义。它是一种界面。

In the code below, if 'virtual display()' is called with a base class pointer (Line 22), it shows an error. Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?

由于指针未初始化,因此会引发错误。像下面这样使用。

Base baseObj1,*basePtr;

basePtr= &baseObj1;

basePtr->Display();  //Inside base class

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    相关资源
    最近更新 更多