假设有一个类Human
,它有一个宠物列表。宠物可以是Cat
或Dog
。为了避免对象切片,我将列表中的对象声明为基类Pet
的指针。
现在,当我想通过拨打operator=
制作人的副本时,我需要检查每只宠物是狗还是猫。有了这种方法,例如,如果我添加一种新类型的宠物,我们称之为Fish
,我必须记住添加(在Human::operator=
内)if语句来检查宠物是否是鱼
我的问题是:是否可以为类Human实现operator=
(或复制构造函数)而无需向下转换(不检查宠物的所有类型)?
class Pet {
public:
virtual std::string getType()=0;
};
class Cat : public Pet {
public:
std::string getType() {
return "Cat";
}
};
class Dog : public Pet {
public:
std::string getType() {
return "Dog";
}
};
class Human {
public:
void addPet(Pet* pet) {
this->pets.push_back(pet);
}
virtual std::list<Pet*> getPets() const {
return this->pets;
}
Human& operator=(const Human& other) {
std::list<Pet*> pets=other.getPets();
std::list<Pet*>::iterator i=pets.begin(), end=pets.end();
for(;i!=end;i++) {
if(dynamic_cast<Cat*>(*i)) {
this->pets.push_back(new Cat);
} else if(dynamic_cast<Dog*>(*i)) {
this->pets.push_back(new Dog);
}
}
return *this;
}
private:
std::list<Pet*> pets;
};
int main()
{
Human* joe=new Human;
joe->addPet(new Cat);
joe->addPet(new Dog);
Human bob=*joe;
delete joe;
std::list<Pet*> pets=bob.getPets();
std::list<Pet*>::iterator i=pets.begin(), end=pets.end();
for(;i!=end;i++) {
std::cout<<(*i)->getType()<<std::endl;
}
}
答案 0 :(得分:3)
通常,您所做的是正确实现每个派生类的复制构造函数(在许多情况下,这意味着只保留默认值)。
然后,在基类中声明类似
的内容virtual Base* clone()=0;
在每个派生类中实现为:
virtual Base* clone()
{
return new Derived(*this);
}
现在,每次要复制类层次结构的对象时,只需调用其clone()
方法即可。这避免了切片,因为被调用的clone版本是实际类型之一,因此调用正确的复制构造函数。
答案 1 :(得分:1)
给Pet
虚拟clone()
方法,然后在需要时调用它,例如:
class Pet
{
public:
virtual ~Pet() {}
virtual std::string getType()=0;
virtual Pet* clone()=0;
};
class Cat : public Pet
{
public:
std::string getType() {
return "Cat";
}
virtual Pet* clone() {
return new Cat(*this);
}
};
class Dog : public Pet
{
public:
std::string getType() {
return "Dog";
}
virtual Pet* clone() {
return new Dog(*this);
}
};
class Human
{
public:
void addPet(Pet* pet) {
this->pets.push_back(pet);
}
virtual std::list<Pet*> getPets() const {
return this->pets;
}
Human& operator=(const Human& other) {
for (std::list<Pet*>::iterator i = this->pets.begin(), end = this->pets.end(); i != end; ++i) {
delete *i;
}
this->pets.clear();
std::list<Pet*> pets = other.getPets();
for (std::list<Pet*>::iterator i = pets.begin(), end = pets.end(); i != end; ++i) {
std::auto_ptr<Pet> pet((*i)->clone());
this->pets.push_back(pet.get());
pet.release();
}
return *this;
}
private:
std::list<Pet*> pets;
};
int main()
{
Human* joe = new Human;
joe->addPet(new Cat);
joe->addPet(new Dog);
Human bob = *joe;
delete joe;
std::list<Pet*> pets = bob.getPets();
for (std::list<Pet*>::iterator i = pets.begin(), end = pets.end(); i != end; ++i) {
std::cout << (*i)->getType() << std::endl;
}
}