将对象转换为其他类
Converting object to a different class
Sandy是Person类,他皈依了穆斯林并取了一个新名字Fatima,并具有Sandy的所有属性,具有新的穆斯林属性(例如宗教==伊斯兰教等(。在这一点上,桑迪可以被删除,现在的穆斯林阶层的法蒂玛将从此扮演桑迪的角色。问题是,由于她的新地址,所有认识桑迪的人都不认识法蒂玛。为所有认识桑迪的人手动将桑迪的地址更改为法蒂玛的地址显然不是一种可接受的方法。关于如何改进设计的任何建议?这是我显示问题的简化代码:
#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
}
输出:
桑迪 = 0x32658,6 人
玛丽最好的朋友是桑迪。
法蒂玛=0x23fec0,6穆斯林
玛丽最好的朋友是桑迪。
当然,我们希望拥有:玛丽最好的朋友是法蒂玛,玛丽->getBestFriend((->getReligion(( == 伊斯兰教等......如何重新设计整个事情,以便自动化(假设有成千上万的人认识她(?
我想使用继承,因为类 Muslim 将有许多复杂的 Person 方法覆盖(以及许多新的数据成员和方法(。
正如@Joseph曼斯菲尔德在评论中建议的那样,我的第一个方法是将religion
作为Person
的属性。因此,更改仅意味着属性的更改,而不是新对象。
不同的类,则可以使用观察者模式。也就是说,任何朋友的人都应该订阅(在朋友通讯录中(列表以更改该人。此订阅服务器必须实现来自同一接口(订阅服务器(的方法,当Person
对象的属性更改时,该方法应由 对象调用。
总结一下:
- 在
Person
(friends
(上列出每个朋友的地址列表。 - 每个友元对象类都应该实现一个公共接口,其中声明了更改通知方法(
friendChanged(...)
( - 当
Person
通过创建新类的新对象进行更改时,它必须遍历其friends
列表,调用friendChanged
并向他们传递新的 person 对象地址。之后,您可以销毁和释放旧对象。
最后,我认为宗教不应该被代表为一个子类。在我看来,宗教是一个人的特征,因此,它应该是一个属性。有一个OOP原则说:赞成组合而不是继承。你的设计似乎人为地违背了这一原则。
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();
}
相关文章:
- 无法将模板子类强制转换为其他模板实例化
- 从 int 中剥离位时,编译器会警告一个转换,但不警告其他转换.有解决方法吗?
- 如何定义此"if block"中其他无效输入的值,以便在c ++中将字符串转换为对象?
- isdigit() 和 isalnum() 给出错误,因为输入是一个常量字符并且无法转换。其他可能查看输入是否为数字的方法?
- 为什么可以将所有类型转换为其他指针类型?
- 驾驶执照考试计划.无法将 std:: 字符串转换为 std :: 字符串和其他错误
- Catch2 迫使我在异常中添加对 std::string 的强制转换,这会产生其他问题吗?
- 如何将 QImage 中的像素数据转换为其他格式
- OpenCV将一种颜色转换为任何其他颜色
- 我可以铸造/将模板转换为其他模板类型
- 无法转换某些类,但其他类可以.C++
- C++ 将时间 ET 转换为 CET 或其他内容
- 如果 JVM 的参数是从其他类型的转换而来的,JNI 找不到该类
- C++ 将部分数组(在某些偏移量)转换为其他类型
- 我应该采取什么方法来将ascii字符转换为c++中的其他字符
- 为什么我不能在窗口上使用 boost::locale::conv::between 将 UTF-16 文本转换为其他编码
- 如何检查Void指针是否可以转换为其他特定的指针类型
- 如何强制转换优先于其他转换
- C++将NSStringwithformat:转换为其他Cocos2dx
- 如何将路径存储在这种结构中,以及如何将其转换为其他内容