我以这种简单的形式提出问题:
class animal {
public:
animal() {
_name="animal";
}
virtual void makenoise(){
cout<<_name<<endl;
}
string get_name(){
return _name;
}
protected:
string _name;
};
class cat : public animal {
public:
cat() {
this->_name="cat";
}
};
class dog : public animal {
public:
dog() {
this->_name = "dog";
}
};
我想将所有动物类型一起存储在一个容器中,例如:
vector<animal*> container;
barnyard.push_back(new animal());
barnyard.push_back(new dog());
barnyard.push_back(new cat());
在代码的某个时刻,我需要将dog对象转换为cat对象。我需要进行的转换是设置一个新的dog对象,并用与cat对应的对象相同的索引号替换它。据我了解,dynamic_cast
在这种情况下不起作用,并且基于C++ cast to derived class,提到这种转换不是一个好习惯。由于模型中的猫和狗具有不同的行为特性,因此我不想将它们的定义放入动物模型中。另一方面,将它们分别存储在不同向量中将很难处理。有什么建议吗?
答案 0 :(得分:7)
您说:
我需要将狗对象转换为猫对象。
但是然后:
从这种转换中,我所需要做的就是设置一个新的Dog对象,并用与猫对应的对象相同的索引号替换它。
您需要转换还是替换它??这是完全不同的操作。
要进行转换,您需要设置一个将狗带回猫的函数:
auto convertDogToCat(Dog const& dog) -> Cat {
auto cat = Cat{};
// fill cat's member using dog's values...
return cat;
}
但是要替换为新的,只需重新分配:
// v--- a cat is currently there
barnyard[ii] = new Dog{};
// ^--- we replace the old pointer
// with one that points to a dog.
但这会造成内存泄漏,要消除此泄漏,只需使用std::unique_ptr
:
#include <memory> // for std::unique_ptr
// The base class need a virtual destructor
class animal {
public:
virtual ~animal() = default;
// other members...
};
std::vector<std::unique_ptr<animal>> barnyard;
barnyard.emplace_back(std::make_unique<animal>());
barnyard.emplace_back(std::make_unique<dog>());
barnyard.emplace_back(std::make_unique<cat>());
barnyard[ii] = std::make_unique<Dog>();
答案 1 :(得分:3)
这是另一种方法。不使用OOP或动态分配,而是为您的示例提供相同的功能。而且,由于不需要分配/释放动态内存,动物也就只有一个字节。
enum struct eAnimalKind : uint8_t
{
Generic = 0,
Cat = 1,
Dog = 2,
};
string get_name( eAnimalKind k )
{
static const std::array<string, 3> s_names =
{
"animal"s, "cat"s, "dog"s
};
return s_names[ (uint8_t)k ];
}
void makenoise( eAnimalKind k )
{
cout << get_name( k ) << endl;
}
如果您的类保留的状态多于一种类型,请使用具有该枚举的一个类作为成员。
如果某些动物使用自定义的字段/属性集,将变得很棘手,但仍然可以实现,用于特定物种状态的嵌套结构以及class animal
中这些结构的std :: variant可以跟踪物种并保持数据。在这种情况下,您不再需要enum eAnimalKind
,std :: variant已经可以跟踪其包含的类型。
经典C ++ OOP需要动态内存。派生的类通常具有不同的sizeof,您不能将它们保持在单个向量中,而只能保留指针,并且在运行时,访问每个元素都会遇到RAM延迟。
如果您的动物又大又复杂,例如兆字节的RAM和昂贵的方法,那很好。但是,如果您的动物很小,包含几个字符串/数字,并且您有很多,那么RAM延迟将破坏OOP方法的性能。