我试图通过这段代码实现一些图解,但我无法让它发挥作用。我无法返回Animal
,我真的不认为返回Animal*
会很好,因为我必须new
和delete
手动。
编辑:我使用更具体的代码段更新了问题,演示了为什么返回Animal*
并不是一个非常好的主意。
正如您从代码段中看到的,我基本上想要使用Animal
一堆数据的接口,该数据可能是数组的一部分
或者它可能是一个更传统的对象。
编辑2 :工作示例:http://ideone.com/4qp3qT
剩下的问题:
FeedAnimals()
)delete
(对于猫)的
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <stdlib.h>
using namespace std;
class Animal {
virtual void eat() = 0;
};
// Dog is more high-level
class Dog: public Animal {
char attr1;
char attr2;
Dog(_attr1, _attr2):
attr1(_attr1),
attr2(_attr2)
{}
Dog():
attr1('d'),
attr2('g')
{}
void eat() {
cout << "Dog ate food (" << attr1 << attr2 << ").\n";
}
void barf() {
cout << "Whaf";
}
};
// Cat is more low-level
class Cat: public Animal {
// A cat can basically only exist in a cage
// and it's attributes are defined by it's location
// in the Cage's underlying array. A Cat should also
// have to 2 attributes (both char), so this would
// be kind of true:
// sizeof(Cat) == 2
char* ptr;
// I will only use a Cat in a context of arrays, so
// no need to care about memory management here.
Cat(char* _ptr):
ptr(_ptr)
{}
void eat() {
cout << "Cat ate food (" << *ptr << *(ptr+1) << ").\n";
}
void meow() {
cout << "Meow.";
}
};
class Cage {
virtual Animal GetRandomAnimal() = 0;
};
// DogCage uses a nice (more high level) vector
class DogCage {
vector<Dog> dogs;
DogCage():
dogs(5)
{}
Animal GetRandomAnimal() {
// ?
}
}
// CatCage uses a more low level pointer together with
// malloc etc.
class CatCage {
char* cats;
CatCage():
cats((char*) malloc(4*2)) // room for 4 cats
{}
~CatCage() {
free(cats);
}
Animal GetRandomAnimal() {
// ...
// This is why it's difficult to return a pointer
// to an Animal. I basically want to use a Cat as
// a simple interface to a part of an array.
// If I use pointers etc, that seems like it would
// hit performance.
return Cat(cats+(random*2))
}
}
void FeedAnimals(Animal& a) {
a.eat();
}
int main() {
Cage cage; // ?
string s;
cout << "Cats or dogs?";
cin >> s;
if (s=="Cats") {
cage = CatCage(); // ?
} else {
cage = DogCage(); // ?
}
// fill cage with animals (either cats or dogs)
FeedAnimals(cage.GetRandomAnimal());
}
答案 0 :(得分:1)
指针不必指向动态对象,只有它们才需要delete
(在这种情况下考虑智能指针)。
在动物的情况下,你可以返回一个参考或指针到笼子里的一只动物。
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>();
}
如果您过去陷入困境,请将unique_ptr
替换为auto_ptr
,boost::scoped_ptr
或手绘等效内容。
答案 1 :(得分:1)
您真正的问题是,您可以随意尝试避免使用可用于该作业的工具(指针,参考或智能指针)。
我猜,这是因为你熟悉其他似乎允许这种语言的语言。事实是,做这些事情的语言是通过以C ++没有的方式混合对象,引用和指针的概念来实现的。
在C ++中无法按值返回抽象类。期。按值返回类意味着必须实例化它,而抽象类是无法实例化的类。
如果函数返回原始引用或指针,则在调用者使用它们时必须存在对象,并且在不再需要时释放(不再存在)对象。这意味着你的函数负责管理对象的生命周期(例如,对象是数组的元素)或调用者是(例如函数动态创建对象,调用者在完成后释放它)。
返回智能指针意味着返回管理所包含对象的生命周期的对象。该函数创建对象,将其交给智能指针,智能指针返回给调用者。当智能指针不再存在时(例如,调用者返回以使其超出范围),该对象将被释放。
答案 2 :(得分:0)
您无法返回Animal
,因为您无法创建Animal
(它是抽象类型)。你需要任何动物(Cat
,Dog
等)可以隐藏的东西:指针或引用。如果您事先创建了所有动物,则可以返回(最好是常量)参考:
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::shared_ptr
和std::make_shared
。
(唉,std :: make_unique是C ++ 14)