将c ++接口实例化为子类

时间:2013-03-23 20:42:27

标签: c++ inheritance interface

我有一个接口,我们称之为Creature,它具有导致它是抽象的虚函数。

我有此界面的子类,例如DogCatPig

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

Creature thing = Dog();

我知道我无法实例化接口等,但这只是Dog被声明为Creature

我需要某种方式让一个声明适用于所有孩子(即能够将Dog()Cat()Pig()放在Dog()所在的位置以上)。

这可以用c ++完成,还是我完全滥用继承和接口?

2 个答案:

答案 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);