【问题标题】:Virtual Copy Constructor [duplicate]虚拟副本构造函数 [重复]
【发布时间】:2013-12-30 11:30:26
【问题描述】:

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

}

【问题讨论】:

  • 下一次,尽量减少你的代码,而不是全部粘贴。 :)
  • 对,对不起。下次我会记住这一点的。
  • 对于 C++11 应该使用 override

标签: c++ constructor virtual-functions


【解决方案1】:

不,没有区别。

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

【讨论】:

  • 但是你能不能进一步覆盖它,比如从 Dog 派生 Akita。析构链还会调用哺乳动物吗?
  • @graham.reeds:它会召唤哺乳动物,没有区别。
【解决方案2】:

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

一般来说,基类和派生类应该有内存分配/资源分配,而不是你需要更小心地使用析构函数并使用虚拟析构函数来调用基类清理。

考虑:

class Base 
{
    // some virtual methods
};

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

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

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

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

特别是在您的情况下,如果 base 类没有用于克隆和复制构造函数的虚拟关键字,则打印输出显然会从 cat/dog/etc.. 更改为哺乳动物。 p>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 2016-04-09
    • 2022-11-17
    • 2010-09-09
    • 2012-04-13
    • 2010-10-02
    相关资源
    最近更新 更多