如何创建抽象类成员

How to make an abstract class member?

本文关键字:抽象类 成员 创建 何创建      更新时间:2023-10-16

假设我有一个名为Foo的类,它不应该被初始化。它必须被继承才能被使用。这使得Foo成为一个没有纯虚函数的抽象类。为了便于示例,我对其进行了简化:

class Foo : Qwe
{
protected:
    Bar& bar;
    int baz;
    Foo(int baz_) : baz(baz_) {}
public:
    virtual void function_that_uses_bar() const override
    {
        // code that uses bar here
    }
}

Foo使用示例:

class Kappa : public Foo
{
public:
    Kappa() : Foo(10)
    {
        bar = Asd(); // Asd is a Bar
    }
}

所以基本上只有从Foo派生的类才知道bar应该设置成什么。

我得到的错误:Error C2530 'Foo::bar': references must be initialized,指的是Foo的构造函数。我该如何解决这个问题?

首先,因为您是在c++中,没有纯虚函数就没有抽象类。这根本就不是一件事。

那么,你的问题是引用必须初始化。看看这段代码:

Bar myBar;
Bar& bar; // Error
bar = myBar; // don't do what you think

这里,在我注释"Error"的那行,这是因为你不能延迟引用的初始化。引用就像另一个变量的别名。引用必须用值初始化

注释"don't do what you think"的那行是因为它不会重新绑定引用。它将调用函数Bar::operator=(const Bar&)。它将使barmyBar的值。

好了,有了这些解释,就更容易理解你的类出了什么问题了。

Foo的构造函数中,有一些隐藏的事情正在进行。

确实,它将用构造函数中获得的值初始化Foo::baz,但它也将初始化类的其他变量,类似于:

//              implicit --v---v
Foo(int baz_) : baz(baz_), bar() {}

看到问题了吗?您正在初始化一个没有变量可引用的引用。您需要引用要绑定的变量。

第二个问题,你在这里做错了:

Kappa() : Foo(10)
{
    bar = Asd(); // Asd is a Bar
}

你的意思是Asd是扩展Bar的类型?如果是这样,您可以将实例bar更改为与空Asd相同的值。是的,它会将空Asd的内容复制到bar。这就是值语义。用户定义的类型的行为就像基本的。


好,那么现在,如何修复这段代码呢?

我假设你想创建一个基类的新实例,并将对父类的引用绑定到该新实例。如果是这样,则需要一个可以超越构造函数作用域的变量:
Kappa() : Foo(10)
{
    Asd myAsd;
    bar = /* somehow bind bar to myAsd */
} // myAsd destroyed here!

如您所见,您必须创建一个必须超过}的变量。理想的情况是,只要Kappa存活,变量的存活时间就足够长。输入std::unique_ptr !

代替不声明所有权的引用,使用std::unique_ptr。它是一个类,表示在自由存储中分配的变量,也就是。堆分配的变量。它的行为类似于java或c#或<插入托管语言名称>。通常使用std::unique_ptrstd::make_unique进行分配。

你可以这样使用:

class Foo : Qwe
{
protected:
    // pointer here, null by default
    std::unique_ptr<Bar> bar;
    int baz;
    Foo(int baz_) : baz(baz_) {}
public:
    virtual void function_that_uses_bar() const override
    {
        // code that uses bar here
    }
}
struct Kappa : Foo
{
    Kappa() : Foo(10)
    {
        // Create a new unique_ptr of Asd and bind it to bar
        bar = std::make_unique<Asd>(); // Asd is a Bar
    }
}