2013-12-12 96 views
1

如果我在每個派生類中的析構函數和Clone()函數之前註釋掉virtual,是否有區別? 他們都產生相同的輸出:虛擬複製構造函數

#include <iostream> 

class Mammal 

{ 

public: 

    Mammal():itsAge(1) { std::cout << "Mammal constructor...\n"; } 

    virtual ~Mammal() { std::cout << "Mammal destructor...\n"; } 

    Mammal (const Mammal & rhs); 

    virtual void Speak() const { std::cout << "Mammal speak!\n"; } 

    virtual Mammal* Clone() { return new Mammal(*this); } 

    int GetAge()const { return itsAge; } 



protected: 

    int itsAge; 

}; 



Mammal::Mammal (const Mammal & rhs):itsAge(rhs.GetAge()) 

{ 

    std::cout << "Mammal Copy Constructor...\n"; 

} 



class Dog : public Mammal 

{ 

public: 

    Dog() { std::cout << "Dog constructor...\n"; } 

    /*virtual*/ ~Dog() { std::cout << "Dog destructor...\n"; } 

    Dog (const Dog & rhs); 

    void Speak()const { std::cout << "Woof!\n"; } 

    /*virtual*/ Mammal* Clone() { return new Dog(*this); } 

}; 



Dog::Dog(const Dog & rhs): 

Mammal(rhs) 

{ 

    std::cout << "Dog copy constructor...\n"; 

} 



class Cat : public Mammal 

{ 

public: 

    Cat() { std::cout << "Cat constructor...\n"; } 

    /*virtual*/ ~Cat() { std::cout << "Cat destructor...\n"; } 

    Cat (const Cat &); 

    void Speak()const { std::cout << "Meow!\n"; } 

    /*virtual*/ Mammal* Clone() { return new Cat(*this); } 

}; 



Cat::Cat(const Cat & rhs): 

Mammal(rhs) 

{ 

    std::cout << "Cat copy constructor...\n"; 

} 



enum ANIMALS { MAMMAL, DOG, CAT}; 

const int NumAnimalTypes = 3; 

int main() 

{ 

    Mammal *theArray[NumAnimalTypes]; 

    Mammal* ptr; 

    int choice,i; 

    for (i = 0; i<NumAnimalTypes; i++) 

    { 

     std::cout << "(1)dog (2)cat (3)Mammal: "; 

     std::cin >> choice; 

     switch (choice) 

     { 

     case DOG: 

      ptr = new Dog; 

      break; 

     case CAT: 

      ptr = new Cat; 

      break; 

     default: 

      ptr = new Mammal; 

      break; 

     } 

     theArray[i] = ptr; 

    } 

    Mammal *OtherArray[NumAnimalTypes]; 

    for (i=0;i<NumAnimalTypes;i++) 

    { 

     theArray[i]->Speak(); 

     OtherArray[i] = theArray[i]->Clone(); 

    } 

    for (i=0;i<NumAnimalTypes;i++) 

     OtherArray[i]->Speak(); 

    return 0; 

} 
+0

下次嘗試最小化您的代碼而不是將它們全部粘貼。 :) –

+0

請參閱http://stackoverflow.com/questions/4895294/c-virtual-keyword-for-functions-in-derived-classes-is-it-necessary –

+0

對,對不起。下次我會記住這一點。 –

回答

1

不,不會有任何區別。

如果繼承上層類的虛函數,派生類會自動獲取virtual屬性。即使你沒有明確地宣佈它們,它們也是虛擬的。

+0

但是你能否進一步重載它,比如從Dog中派生出秋田。摧毀鏈仍然會呼喚哺乳動物? –

+0

@ graham.reeds:它會喚起哺乳動物,沒有任何區別。 – David

0

在你展示的例子中,沒有區別。

一般來說,基類和派生類有內存分配/資源分配,比你需要更仔細地使用析構函數並使用虛擬析構函數來調用基類清除。

考慮:

class Base 
{ 
    // some virtual methods 
}; 

class Derived : public Base 
{ 
    ~Derived() 
    { 
     // Do some important cleanup 
    } 
} 

Base *b = new Derived(); 
delete b; 

在呼籲刪除b當上面的場景中,你會調用基類的析構函數和派生類沒有析構函數,因此可能會導致資源泄漏。

所以在你的場景中沒有區別,因爲基類聲明瞭這些函數的虛擬關鍵字,但是,如果你從基類中刪除它,你將遇到問題,如上面我的scneario中所述。

特別是在你的情況下,打印輸出顯然會從cat/dog/etc改變爲哺乳動物,如果基類類沒有克隆和複製構造函數的虛擬關鍵字。