虚拟复制构造函数

Virtual Copy Constructor

本文关键字:构造函数 复制 虚拟      更新时间:2023-10-16

如果在每个派生类中的析构函数和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;
}

不,没有区别。

如果派生类继承了上层类的虚拟函数,它们将自动获得virtual属性。即使你没有明确宣布,它们也是虚拟的。

在您展示的示例中没有任何区别。

通常,如果基类和派生类有内存分配/资源分配,那么您需要更小心地使用析构函数,并使用虚拟析构函数来调用基类清理。

考虑:

class Base 
{
    // some virtual methods
};
class Derived : public Base
{
    ~Derived()
    {
        // Do some important cleanup
    }
}
Base *b = new Derived();
delete b;

在上面的场景中,当调用delete b时,您将调用基类的析构函数,而不调用派生类的析构因子,因此可能导致资源泄漏。

因此,在您的场景中没有区别,因为基类为这些函数声明了虚拟关键字,但是,如果您将其从基类中删除,您将遇到上面我的scneario中描述的问题。

特别是在你的情况下,打印出来的东西显然会从猫/狗/等改变。。对于哺乳动物,如果基类将没有用于克隆和复制构造函数的虚拟关键字。