我有一些没有复制构造函数的类( Window )(它是私有的)。我无法理解如何在我自己的类中初始化此类的变量:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
void init()
{
obj = Window(/* constructor params */); // [error]
obj(/* constructor params */); // [error]
}
}
错误1 :initializing argument 1 of ‘Window::Window(WindowHandle, const sf::WindowSettings&)’
错误2 :‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’ is private
但它的工作原理如下:
Window obj(/* constructor params */);
答案 0 :(得分:6)
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass() :
obj(/* constructor params */)
{
}
}
这也适用于参考。您可以在初始化列表中分配任何成员变量。但它只适用于构造函数。
如果您希望它在构造函数外部工作,则需要使用指针:
class MyClass
{
Window *obj;
public:
void init()
{
obj = new Window(/* constructor params */);
}
}
请务必在解构程序中使用obj
取消分配delete
(并在必要时将解构函数设为虚拟)。
答案 1 :(得分:4)
您的MyClass
需要构造函数来初始化obj
成员。
class MyClass
{
private:
Window obj;
public:
MyClass() : obj(/* constructor params */) // This is an initializer list
{}
};
如果您需要init()
函数,Window
对象提供了自己的函数
init()
某种功能,你可以这样做:
class MyClass
{
private:
Window obj;
public:
void init()
{
obj.init(/* init params */); // Window's own init() function
}
};
如果Window
类没有像init()
函数那样的东西,你可以使用堆(除非你绝对需要,否则不推荐):
class MyClass
{
private:
// Alternatively, we can use a smart pointer here and avoid
// managing memory ourselves.
Window* obj;
public:
MyClass() : obj(0) {}
~MyClass() { uninit(); }
void init()
{
uninit();
obj = new Window(/* constructor params */);
}
void uninit()
{
if(obj != 0)
{
delete obj;
obj = 0;
}
}
};
如果Window
类声明了私有拷贝构造函数和/或拷贝赋值运算符,则无法将新Window
实例分配给obj
。
答案 2 :(得分:1)
如果您的复制构造函数是私有的,则类具有复制构造函数。看来你的类有复制ctor和赋值操作为私有,这解释了第二个错误消息。第一条错误消息与WindowHandle类有关,你没有显示它。
为了更好地理解这一点,我们还需要看到Window类 - 它(例如)是否有默认的构造函数?
答案 3 :(得分:1)
我想我会彻底被彻底删除(直到最后才开始冒烟)但是......假设windows的构造函数从不抛出:
void MyClass::init()
{
obj::~Window(); // destroy the object
new (&obj) Window(...); // construct the object
};
我当然会强调构造函数的 not throw 要求,好像它会抛出你会留下一个非常混乱的情况:MyClass
的析构函数将调用析构函数Window
,无论对象是否因为构造失败而活着,踢或被破坏,在后一种情况下,您会得到未定义的行为。
当然,典型的事情将是std::unique_ptr<Window>
,但我们有动态分配的障碍,显然情况并非强制要求......
因此,您最好使用图书馆:Boost.Optional。
class MyClass
{
public:
private:
boost::optional<Window> obj;
};
语法调用类似于指针:
obj->foo();
但唯一的好处是你可以使用更安全的语义来实现破坏/构建。毁灭很容易:
// both call ~Window() if an instance had been constructed
obj.reset();
obj = detail::none_t();
施工时使用TypedInPlaceFactory。而且对于赋值...当然首先清除前一个实例(如果有的话):
void MyClass::init(Arg1 arg1, Arg2 arg2)
{
obj = boost::in_place<Window>(arg1, arg2);
}
主要优点是,如果在构造期间现在遇到任何异常,optional
对象将保持unitialized
状态,这是完全可行的,因此您不必担心未定义的行为。< / p>
所以基本上就像拥有一个由智能指针拥有的动态分配的对象......除了神奇的是对象没有被动态分配,从而保证了与“普通”对象完全相同的性能:)
我应该补充说,不可复制的障碍是InPlaceFactory创建背后的原因之一。
答案 4 :(得分:0)
重点是不要让你克隆它。
像这样初始化:Window obj(其他构造函数的参数,而不是副本的参数)
或
Window&amp; obj = somefunctionConstructingSuchAWindow();
答案 5 :(得分:0)
如果Window
没有复制构造函数,则无法为其分配另一个类Window
的对象。您只能使用初始化列表从obj
的构造函数初始化MyClass
。例如:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass()
: obj(/*constructor params*/)
{
/*...*/
}
}
答案 6 :(得分:0)
类成员的初始化应该在类构造函数上完成,如下例所示:
class MyClass
{
public:
MyClass(/* constructor params */);
private:
Window m_obj; // Hasn't copy constructor
};
MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */)
{
}