我有一个接口,我们称之为Creature
,它具有导致它是抽象的虚函数。
我有此界面的子类,例如Dog
,Cat
和Pig
。
由于无法将变量thing
声明为抽象类型Creature
,编译器似乎不喜欢以下行。
Creature thing = Dog();
我知道我无法实例化接口等,但这只是Dog
被声明为Creature
。
我需要某种方式让一个声明适用于所有孩子(即能够将Dog()
,Cat()
或Pig()
放在Dog()
所在的位置以上)。
这可以用c ++完成,还是我完全滥用继承和接口?
答案 0 :(得分:8)
对象类型本身在C ++中不是多态的。您给出的行声明了一个Creature
对象,然后尝试使用Dog
对象初始化它。如果Creature
不是抽象的,那么会导致切片 - thing
不再是Dog
,它只是Creature
。由于它是抽象的,你无论如何都不能拥有Creature
个对象。
您需要使用指针或引用来进行多态行为。考虑例如:
Creature* thing = new Dog();
您现在可以取消引用thing
并将其用作Creature
,即使它的动态类型为Dog
。但是,通常不建议使用这样的原始指针,因为您必须在某个时刻手动确保对象为delete
d。所有权可能会变得混乱。最好的办法是将它放在智能指针中,例如:
std::unique_ptr<Creature> thing(new Dog()); // or std::make_unique when we have it
在这里,我演示了std::unique_ptr
,但智能指针的选择将取决于该对象的所有权语义。常见的替代方案是std::shared_ptr
。
用引用来证明多态性:
Dog dog;
Creature& thing = dog;
// Can now use dog as a Creature
答案 1 :(得分:1)
在C ++中你必须意识到值和引用语义之间的差异,在解释语言中你倾向于只处理引用语义(除了一些奇怪的情况,普通的旧数据对象具有值语义但除了点之外)。
在C ++中,所有对象都是值,例如,对象永远不能是null
,这意味着声明指定了存储要求。
请考虑以下
struct creature {
};
struct dog : public creature {
float cuteness;
};
狗的存储要求与生物的存储要求不同,即使您允许转换也会导致切片。 例如,fido会吠叫还是保持沉默? #include
class creature {
public:
virtual void speak() {
std::cout << "..." << std::endl;
}
};
class dog : public creature {
public:
virtual void speak() {
std::cout << "woof!" << std::endl;
}
};
int main(int argc, const char *argv[]) {
creature fido;
fido = dog();
fido.speak();
return 0;
}
但是,如果你只是想要一个指针或对象的引用,那是另一回事。 通过指针。
creature* fido = new dog();
fido->speak();
delete fido;
参考。
dog fido;
creature& c = fido;
c.speak();
超出了这个问题的范围,但可选择智能指针。
std::unique_ptr<creature> fido(new dog);