为什么“基类对象”不能称之为自己的虚函数? C ++

时间:2014-09-02 13:11:53

标签: c++ polymorphism virtual-functions

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

困扰我的问题是:

  1. 为什么在基类中声明一个具有相同名称的函数,如果它最终必须被声明为虚拟? (注意:我需要关于虚函数的多态方面的答案)
  2. 在下面的代码中,如果'虚拟显示()'使用基类指针(第22行)调用,它显示错误。为什么C ++中的虚函数如此严格w.r.t.没有被基类指针调用?
  3. #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;
    }
    

    输出:

    内部派生类。

3 个答案:

答案 0 :(得分:2)

b是指针而不是对象。最初它没有指向任何东西(因此通过它是间接的错误);在b = &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 ++中的虚函数如此严格w.r.t.没有被基类指针调用?

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

答案 1 :(得分:0)

我承认我不太明白你的问题#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;
}

答案 2 :(得分:0)

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

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

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