Init var没有复制构造函数

时间:2010-05-29 13:10:04

标签: c++ constructor copy init

我有一些没有复制构造函数的类( 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 */);

7 个答案:

答案 0 :(得分:6)

使用initializer list

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 */)
{
}