如果我要在每个派生类中的析构函数和virtual
函数之前注释Clone()
,有什么区别吗?
它们都产生相同的输出:
#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 :(得分:1)
不,没有区别。
如果派生类继承了上层类的虚函数,则会自动获得virtual
属性。即使你没有明确宣布它们,它们也是虚拟的。
答案 1 :(得分:0)
在你展示的例子中,没有区别。
通常,基类和派生类应该具有内存分配/资源分配,而不是需要更仔细地使用析构函数并使用虚拟析构函数来调用基类清理。
考虑:
class Base
{
// some virtual methods
};
class Derived : public Base
{
~Derived()
{
// Do some important cleanup
}
}
Base *b = new Derived();
delete b;
在上面的方案中,当调用delete b时,你会调用基类的析构函数而不是派生类的析构函数,因此可能导致资源泄漏。
因此在您的场景中没有区别,因为基类为这些函数声明了虚拟关键字,但是,如果您从基类中删除它,您将遇到上述我的scneario中描述的问题。
特别是在您的情况下,如果 base 类没有用于克隆和复制构造函数的虚拟关键字,打印输出显然会从cat / dog / etc变为哺乳动物。