在不知道类结构的情况下重载赋值运算符

时间:2014-03-26 18:17:50

标签: c++ operator-overloading

假设有一个类Human,它有一个宠物列表。宠物可以是CatDog。为了避免对象切片,我将列表中的对象声明为基类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;
   }
}

2 个答案:

答案 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;
    }
}