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