首页 文章

为什么't a '基类对象' call it'拥有自己的虚函数? C

提问于
浏览
4

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

困扰我的问题是:

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

  • 在下面的代码中,如果使用基类指针(第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;
}

Output:

里面的派生类 .

3 回答

  • 0

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

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

    为什么在基类中声明一个具有相同名称的函数,如果最终必须将其声明为虚拟?

    它需要在基类中声明,以便在使用指向基类的指针时,编译器知道它存在 . 是否通过指针调用函数将调用基类版本,或者由派生类重写的版本取决于对象的类型 .

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

    那个's because it doesn'指向任何东西,所以使用它是一个错误 . 如果它指向一个 B 对象,那么它将调用 B 中声明的函数 .

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

    为什么C中的虚函数如此严格w.r.t.没有被基类指针调用?

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

  • 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;
    }
    
  • 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
    

相关问题