2017-02-16 58 views
2

我正在查看虚拟功能行为的示例情况。鉴于这个测试代码,我有几个关于它的行为的问题。虚拟功能签名不匹配及其行为

class A 
{ 
public: 
    A(int x) 
    { 
     cout << "In A Constructor" << endl; 
     print(); 
    } 
    ~A(){ 
     cout << "In A Destructor" << endl; 
     delete _val; 
    } 
    virtual void print() { cout << "A." << endl; } 
private: 
    char* _val; 
}; 

class B: public A 
{ 
public: 
    B(int x, int y) : A(x) 
    { 
     _dVal = new char[y]; 
     cout << "In B Constructor 1" << endl; 
     print(); 
    } 
    B() : A(0) 
    { 
     _dVal = new char[1]; 
     cout << "In B Constructor 2" << endl; 
     print(); 
    } 
    ~B(){ 
     cout << "In B Destructor" << endl; 
     delete _dVal; 
    } 
    void print() { cout << "B" << endl; } 
private: 
    char* _dVal; 
}; 

int main(int argc, char** argv) { 
    A* p1 = new B(); 
    p1->print(); 
    delete p1; 
    return 0; 
} 

的输出是:

In A Constructor 
A. 
In B Constructor 2 
B 
B 
In A Destructor 

1)为什么被称为B类打印如果类A是唯一一个表示它作为一个虚函数和它正被解除引用(称为 - > )? 2)如果构造函数实际上被调用,为什么B的析构函数永远不会被调用?

+1

如果函数在基类中是虚拟的,那么它在所有派生类中也是虚拟的。同样是析构函数。 –

+1

请问每个问题一个问题。 –

回答

4

1)为什么打印要求类B,如果类A是唯一一个表示它是一个虚函数,并且被解引用( - >)调用?

这就是虚拟功能应该做的事情。指针p1的类型为A*,但实际上它指向的是B类型的对象。而这种动态绑定仅在派生类使用指针或对基类的引用进行处理时才会发生。

另请注意,派生类中的覆盖函数也是virtual(无论关键字virtual是否在其声明中使用)。

2)为什么如果构造函数实际上被调用,B的析构函数永远不会被调用?

B析构函数不被调用,因为你不声明基类的析构函数(即A::~A)为virtual destructor。这种情况的行为是不确定的。 B的构造函数被调用是因为您构造B明确由new B()

+0

有趣。由于行为未定义,这是否意味着B类的_dVal会变成oprhan并导致内存泄漏呢? – w0ffen

+0

@ user49096从你观察到的结果来看,是的。请注意,它是不确定的,任何事情都是可能的。 – songyuanyao

+0

@ user49096“_因为行为是不确定的,这是否意味着_”不,它意味着发生的事情没有被定义,未定义,未知...... – curiousguy