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

Instantiating c++ interface as a child class

本文关键字:子类 实例化 接口 c++      更新时间:2023-10-16

我有一个接口,我们叫它Creature,它有虚函数,使得它是抽象的。

我有这个接口的子类,如Dog, CatPig

编译器似乎不喜欢下面的行,因为不能将变量thing声明为抽象类型Creature

Creature thing = Dog();

我知道我不能实例化接口之类的东西,但这只是将Dog声明为Creature

我需要某种方式有一个声明工作为所有的孩子(即,能够把Dog(), Cat(),或Pig(),其中Dog()是在上面的行)。

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

对象类型本身在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

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

在c++中所有的对象都是值,例如一个对象永远不能是null,这意味着声明指定了存储需求。考虑下面的

struct creature {
};
struct dog : public creature {
    float cuteness;
};

狗的存储需求与生物不同,即使允许转换,也会导致切片。比如,狗狗会叫还是会沉默?# 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);