假设我有两个c++类:

class A
{
public:
  A() { fn(); }

  virtual void fn() { _n = 1; }
  int getn() { return _n; }

protected:
  int _n;
};

class B : public A
{
public:
  B() : A() {}

  virtual void fn() { _n = 2; }
};

如果我写下面的代码:

int main()
{
  B b;
  int n = b.getn();
}

有人可能认为n被设为2。

结果是n被设为1。为什么?


当前回答

我看不出这里虚拟关键词的重要性。B是一个静态类型变量,它的类型由编译器在编译时确定。函数调用不会引用虚表。当b被构造时,它的父类的构造函数被调用,这就是为什么_n的值被设置为1。

其他回答

我刚刚在一个程序中出现了这个错误。 我有这样的想法:如果方法在构造函数中被标记为纯虚函数会发生什么?

class Base {
public:
    virtual int getInt() = 0;
    
    Base(){
        printf("int=%d\n", getInt());
    }
};

class Derived : public Base {
    public:
        virtual int getInt() override {return 1;}
};

和…有趣的事情!你首先得到编译器的警告:

warning: pure virtual ‘virtual int Base::getInt() const’ called from constructor

和一个来自ld的错误!

/usr/bin/ld: /tmp/ccsaJnuH.o: in function `Base::Base()':
main.cpp:(.text._ZN4BaseC2Ev[_ZN4BaseC5Ev]+0x26): undefined reference to `Base::getInt()'
collect2: error: ld returned 1 exit status

这是完全不合逻辑的,你只得到一个警告从编译器!

原因是c++对象的构造就像洋葱,由内而外。基类在派生类之前构造。所以,在生成B之前,必须先生成a。当调用A的构造函数时,它还不是B,因此虚函数表中仍然有A的fn()副本的条目。

Firstly,Object is created and then we assign it 's address to pointers.Constructors are called at the time of object creation and used to initializ the value of data members. Pointer to object comes into scenario after object creation. Thats why, C++ do not allows us to make constructors as virtual . .another reason is that, There is nothing like pointer to constructor , which can point to virtual constructor,because one of the property of virtual function is that it can be used by pointers only.

虚函数用于动态赋值,因为构造函数是静态的,所以我们不能将它们设为虚函数。

c++ FAQ Lite很好地涵盖了这一点:

本质上,在调用基类构造函数期间,对象还不是派生类型,因此调用的是基类型的虚函数实现,而不是派生类型的实现。

虚表是由编译器创建的。 类对象有一个指向虚表的指针。当它开始生命时,虚表指针指向虚表 基类的。在构造函数代码的末尾,编译器生成重新指向虚表指针的代码 到类的实际虚函数表。这样可以确保调用虚函数的构造函数代码调用 这些函数的基类实现,而不是类中的重写。