C++ C++;:将抽象类型作为接口返回

C++ C++;:将抽象类型作为接口返回,c++,subclassing,C++,Subclassing,我试图用这段代码实现一些说明,但我无法让它工作。我不能返回动物,而且我真的不认为返回动物*是一个好的解决方案,因为我必须手动创建新的和删除 编辑:我用更具体的代码片段更新了这个问题,演示了为什么返回动物*不是一个好主意 正如您从片段中看到的,我基本上希望使用动物作为 用于一组数据的接口,该数据可能是数组的一部分 或者它可能是一个更传统的物体 编辑2:工作示例: 遗留问题: 重复代码(FeedAnimals()) 表演 必须手动删除(针对猫) #包括 #包括 #包括 #包括 #包括 使用名称

我试图用这段代码实现一些说明,但我无法让它工作。我不能返回
动物
,而且我真的不认为返回
动物*
是一个好的解决方案,因为我必须手动创建
新的
删除

编辑:我用更具体的代码片段更新了这个问题,演示了为什么返回
动物*
不是一个好主意

正如您从片段中看到的,我基本上希望使用
动物作为
用于一组数据的接口,该数据可能是数组的一部分
或者它可能是一个更传统的物体

编辑2:工作示例:

遗留问题:

  • 重复代码(
    FeedAnimals()
  • 表演
  • 必须手动
    删除
    (针对猫)

#包括
#包括
#包括
#包括
#包括
使用名称空间std;
类动物{
虚空eat()=0;
};
//狗更高级
犬类:公共动物{
字符属性1;
字符属性2;
狗(_attr1,_attr2):
属性1(_attr1),
属性2(属性2)
{}
狗():
属性1('d'),
属性2('g')
{}
空吃{

cout你不能返回
动物
,因为你不能创建
动物
(它是一种抽象类型)。你需要任何动物(
,等等)都可以隐藏的东西:指针或引用。如果你事先创建了所有动物,你可以返回(最好是常量)引用:

Cat cat;
Dog dog;

Animal const& GetRandomAnimal()
{
    if (rand() == 42) {
        return cat;
    }
    else {
       return dog;
    }
}
但是,如果要返回以前不存在的动物对象(实例),唯一的选择是在堆上创建并返回指针。返回指针存在的问题是不清楚谁负责删除该对象。使用C++11,最好返回智能指针:

std::unique_ptr<Animal> GetRandomAnimal()
{
    if (rand() == 42) {
        return std::make_unique<Cat>(/*args to the cat constructor*/);
    }
    else {
        return std::make_unique<Dog>(/*args to the dog constructor*/);
    }
}
std::unique_ptr GetRandomAnimal()
{
如果(rand()==42){
返回std::make_unique(/*参数到cat构造函数*/);
}
否则{
返回std::make_unique(/*args给dog构造函数*/);
}
}
或者使用
std::shared_ptr
std::make_shared

(唉,STD::MaMax是C++ 14)

> P>指针不必指向动态对象,只要需要,就可以执行<代码>删除>代码(在这种情况下考虑智能指针)。 对于动物,您只需返回笼子中某个动物的引用或指针

Animal & GetRandomAnimal() {
    return cats[GetRandomIndex()];
}
对于框架本身,动态分配是使其多态的最简单方法;但您应该使用智能指针,以避免在
delete
和调试内存泄漏时胡闹

std::unique_ptr<Cage> cage;

if (s=="Cats") {
    cage.reset(new CatCage); // C++14: cage = std::make_unique<CatCage>();
} else {
    cage.reset(new DogCage); // C++14: cage = std::make_unique<DogCage>();
}
std::唯一的ptr框架;
如果(s==“猫”){
reset(新CatCage);/C++14:cage=std::make_unique();
}否则{
reset(new DogCage);/C++14:cage=std::make_unique();
}

如果你停留在过去,用
auto\u ptr
boost::scoped\u ptr
,或者一个手摇的等价物来替换
unique\u ptr

你真正的问题是你任意地试图避免使用作业可用的工具(指针、引用或智能指针)

我猜,这是因为你熟悉一些其他语言,似乎允许这样做。事情是这样做的语言通过将对象、引用和指针的概念混合在C++中不做。 在C++中,不可能按值返回一个抽象类。按值返回一个类意味着需要实例化它,而抽象类是不能实例化的类。

如果函数返回原始引用或指针,则调用者使用对象时,对象必须存在,不再需要时,对象必须释放(不再存在)。这意味着函数接受管理对象生存期的责任(例如,对象是数组的一个元素),或者调用者是(例如,函数动态创建对象,调用方在完成时释放它)


返回智能指针意味着返回一个管理所包含对象生存期的对象。该函数创建该对象,将其交给智能指针,并将智能指针返回给调用方。当智能指针不再存在时(例如,调用方返回,使其超出范围),对象被释放。

由于类型是抽象的,您不能按值返回,您无论如何也不想这样做,因为您在对象切片方面会遇到问题。您需要通过指针或引用返回。请参阅问题和答案“狗和猫住在一起,集体歇斯底里!”。如果我使用指针等,这似乎会影响性能首先让某些东西工作起来。以最合乎逻辑的方式实现它。然后,如果你有性能问题,考虑优化它。@Jacobins我用一个工作示例的链接更新了这个问题。现在我被卡住了。我将代码段改得更具体,演示了为什么要使用指针(或智能指针)在这种情况下远远不是完美的。当rand()==42时,是否应该返回一个白鼠标?我只想能够编写可以将
Cage
作为参数的函数,并使
Cage
包含
动物
s(因为函数不知道Cage的确切类型)我可以调用方法。<代码> CAT/CODE>特别是低级的,它基本上是处理数组的一部分的方法。我可以用一组函数替换<代码> CAT/COD>来保持它们的有效性,但是这似乎是针对C++的OOP原则。如果是这样的话,你就不需要返回一个动物(或猫)。总之,因为它代表了Cage对象中的实现细节,您的函数不需要以任何方式访问它们
std::unique_ptr<Cage> cage;

if (s=="Cats") {
    cage.reset(new CatCage); // C++14: cage = std::make_unique<CatCage>();
} else {
    cage.reset(new DogCage); // C++14: cage = std::make_unique<DogCage>();
}