将对象转换为其他类

时间:2014-06-22 16:29:58

标签: c++ class

桑迪是一类人物,他皈依穆斯林,取名为法蒂玛,具有桑迪的所有属性,具有新的穆斯林属性(例如宗教==伊斯兰教等等)。在这一点上,桑迪可以被删除,现在穆斯林阶级的法蒂玛将扮演桑迪的角色。问题在于,由于她的新地址,所有认识桑迪的人都不了解法蒂玛。对所有认识桑迪的人来说,手动将桑迪的地址改为法蒂玛的地址显然不是一种可接受的方法。有关如何改进设计的任何建议?这是我的简化代码,显示了问题:

#include <iostream>
#include <string>
#include <typeinfo>

class Person {
        std::string name;
        Person* bestFriend;
    public:
        Person (const std::string& newName) : name (newName) {}
        virtual ~Person() = default;
        std::string getName() const {return name;}
        void setName (const std::string& newName) {name = newName;}
        Person* getBestFriend() const {return bestFriend;}
        void setBestFriend (Person* newBestFriend) {bestFriend = newBestFriend;}
};

class Muslim: public Person {
    public:
        Muslim (const Person& person) : Person (person) {
                          // religion = Islam; etc... 
                }
};

int main() {
    Person *mary = new Person ("Mary"), *sandy = new Person ("Sandy");
    mary->setBestFriend (sandy);
    std::cout << "sandy = " << sandy << ", " << typeid(*sandy).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->
    getName() << "." << std::endl;
    Muslim* fatima = new Muslim (static_cast<Muslim>(*sandy));  // the big change
    fatima->setName ("Fatima");  // should now delete sandy, because fatima takes on every attribue of sandy
    std::cout << "fatima = " << fatima << ", " << typeid(*fatima).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->
    getName() << "." << std::endl;  // still Sandy, of course
}

输出:

sandy = 0x32658,6Person

玛丽最好的朋友是桑迪。

fatima = 0x23fec0,6Muslim

玛丽最好的朋友是桑迪。

当然,我们希望:玛丽最好的朋友是法蒂玛,有玛丽 - > getBestFriend() - &gt; getReligion()==伊斯兰教等...... 如何重新设计整个事物以使其自动化(假设有成千上万的人认识她)?

我想使用继承,因为类穆斯林会对Person方法(以及许多新的数据成员和方法)有许多复杂的覆盖。

2 个答案:

答案 0 :(得分:1)

我的第一种方法是,正如@Joseph Mansfield在评论中建议的那样,religion属性为Person。因此,更改只会意味着属性的更改而不是新的对象。

尽管如此,如果要为您设置不同的类,则可以使用观察者模式。也就是说,任何一个人的朋友都应该订阅(在朋友地址簿中)列表给人改变。该订户必须实现来自同一接口(订户)的方法,当其属性发生变化时,该方法应由Person对象调用。

总结一下:

  • Personfriends)为每位朋友提供地址列表。
  • 每个朋友对象类都应该实现一个公共接口,其中声明了更改通知方法(friendChanged(...)
  • Person通过创建新类的新对象而发生更改时,它必须遍历调用friends的{​​{1}}列表并向其传递新的人物对象地址。之后,您可以销毁和取消分配旧对象。

最后,我不认为宗教应该被表示为一个子类。宗教对我来说是一个人的特征,因此,它应该是一个属性。有一个OOP原则说:Favor composition over inheritance。你的设计似乎是人为地反对这个原则。

答案 1 :(得分:0)

class Person;

class ObserverPersonInterface {
    public:
        virtual void registerObserver (Person*) = 0;
        virtual void removeObserver (Person*) = 0;
        virtual void notifyObservers() const = 0;       
};

class AddressChangeData : public ObserverPersonInterface {
    public:
        void addressChange (const Person* oldPerson, Person* newPerson) {
            oldAddress = oldPerson;
            newAddress = newPerson;
            // observers.remove (oldAddress);  // but not relevant here
            notifyObservers();
        }
        virtual void registerObserver(Person* person) override {
            observers.emplace_back (person);
        }
        virtual void removeObserver(Person* person) override {
            observers.remove (person);
        }
    private:
        virtual inline void notifyObservers() const override;

        std::list<Person*> observers;  // should perhaps be a red-black tree for greater efficiency
        const Person *oldAddress;
        Person *newAddress;
} changeOfAddressData;

class Person {
    public:
        Person() {
            changeOfAddressData.registerObserver(this);
        }
        // every new Person constructed is registered to changeOfAddressData
        Person(const std::string& newName) : name (newName) {
            changeOfAddressData.registerObserver (this);
        }
        virtual ~Person() = default;
        std::string getName() const {return name;}
        void setName (const std::string& newName) {name = newName;}
        Person* getBestFriend() const {return bestFriend;}
        void setBestFriend (Person* newBestFriend) {bestFriend = newBestFriend;}
    protected:
        void notifyChangeOfAddress(const Person* oldAddress, Person* newAddress) const {
            changeOfAddressData.addressChange (oldAddress, newAddress);
            delete oldAddress;
        }
    private:
        std::string name;
        Person* bestFriend;

};

class Muslim : public Person {
    public:
        Muslim() = default;
        Muslim(const Person& person) : Person(person) {
            changeOfAddressData.registerObserver (this);
            notifyChangeOfAddress (&person, this);
        }
};

inline void AddressChangeData::notifyObservers() const {
    for (Person* x : observers) {
        if(x->getBestFriend() == oldAddress) {
            x->setBestFriend(newAddress);
        }
    }
}

int main() {
    Person *mary = new Person ("Mary"), *sandy = new Person ("Sandy");

    mary->setBestFriend (sandy);
    sandy->setBestFriend (mary);

    std::cout << "mary = " << mary << ", " << typeid(*mary).name() << std::endl;
    std::cout << "sandy = " << sandy << ", " << typeid(*sandy).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->getName() << "." << std::endl;
    std::cout << sandy->getName() << "'s best friend is " << sandy->getBestFriend()->getName() << "." << std::endl;

    Muslim* fatima = new Muslim(static_cast<Muslim>(*sandy));

    // all subscribers of changeOfAddressData notified of sandy's address change, sandy is deleted automatically
    fatima->setName("Fatima");

    std::cout << "fatima = " << fatima << ", " << typeid(*fatima).name() << std::endl;
    std::cout << mary->getName() << "'s best friend is " << mary->getBestFriend()->getName() << "." << std::endl;
    std::cout << fatima->getName() << "'s best friend is " << fatima->getBestFriend()->getName() << "." << std::endl;

    Muslim* shazia = new Muslim (static_cast<Muslim>(*mary));
    // all subscribers of changeOfAddressData notified of mary's address change, mary is deleted automatically
    shazia->setName ("Shazia");

    std::cout << "shazia = " << shazia << ", " << typeid(*shazia).name() << std::endl;
    std::cout << shazia->getName() << "'s best friend is " << shazia->getBestFriend()->getName() << "." << std::endl;
    std::cout << fatima->getName() << "'s best friend is " << fatima->getBestFriend()->getName() << "." << std::endl;

    std::cin.get();
}