如何创建一个抽象类成员?

时间:2016-11-17 20:23:06

标签: c++ inheritance polymorphism

假设我有一个名为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的构造函数。 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:1)

在其他任何事情之前,因为你使用的是C ++,所以没有没有纯虚函数的抽象类。这根本不是一件事。

然后,您的问题是必须初始化引用。看看这段代码:

Bar myBar;
Bar& bar; // Error

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

这里,在我评论“错误”的行上,这是因为你不能延迟引用的初始化。引用就像是另一个变量的别名。参考必须用值初始化。

评论的行“不要做你认为的”,因为它不会重新引用引用。它将调用函数Bar::operator=(const Bar&)。它会使bar取值为myBar

好的,通过解释,您可以更轻松地了解班上出了什么问题。

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_ptr旁边使用std::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
    }
}