2

我有一个接口,我们称之为它Creature,它具有使其成为抽象的虚函数。

我有这个接口的子类,例如DogCatPig

由于无法将变量声明thing为抽象类型,编译器似乎不喜欢以下行Creature

Creature thing = Dog();

我知道我不能实例化接口等,但这只是一个Dog被声明为Creature.

我需要某种方式让所有孩子都可以使用一个声明(即,能够将Dog(),Cat()Pig()whereDog()放在上面的行中)。

这可以在 C++ 中完成还是我完全滥用继承和接口?

4

2 回答 2

9

对象类型本身在 C++ 中不是多态的。您给出的行声明了一个Creature对象,然后尝试用一个Dog对象对其进行初始化。如果Creature不是抽象的,这将导致切片 -thing不再是 a 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
于 2013-03-23T20:45:22.010 回答
1

在 C++ 中,您必须意识到值语义和引用语义之间的区别,而在解释语言中,您倾向于只处理引用语义(除了一些奇怪的情况,即具有值语义的普通旧数据对象,但除此之外)。

在 C++ 中,所有对象都是值,例如对象永远不可能是null,这意味着声明指定了存储要求。考虑以下

struct creature {
};

struct dog : public creature {
    float cuteness;
};

狗的存储要求与生物的存储要求不同,即使您允许转换,这也会导致切片。例如,fido 会吠叫还是保持沉默?#包括

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);
于 2013-03-23T21:49:11.640 回答