2010-05-29 37 views
1

我有一些类(窗口)没有复制构造函数(它是私有的)。我不明白如何初始化此类的VAR在我自己的类:初始变量没有复制构造函数

class MyClass 
{ 
    Window obj; // Hasn't copy constructor 
    public: 
     void init() 
     { 
     obj = Window(/* constructor params */); // [error] 
     obj(/* constructor params */); // [error] 
     } 
} 

错误1initializing argument 1 of ‘Window::Window(WindowHandle, const sf::WindowSettings&)’

错误2‘NonCopyable& NonCopyable::operator=(const NonCopyable&)’ is private

但它以这种方式工作:

Window obj(/* constructor params */); 
+0

是否有你的类使用'init()'成员函数而不是使用__constructor__的原因? – sbi 2010-05-29 13:21:48

+0

@sbi,是的,有。不要asky为什么=) – Ockonal 2010-05-29 13:24:59

+0

我重新说:你有使用'init()'成员的__good__原因吗? (一个很好的理由是,例如,如果初始化需要调用虚函数,那么需要两步构造。) – sbi 2010-05-29 22:34:32

回答

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

+5

删除一个空指针是[安全](http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.8),所以你不需要'if(obj! = 0)'检查uninit函数。 – 2010-05-29 13:48:11

+0

当且仅当它是默认的全局删除并且全局删除不是越野时,调用NULL指针上的删除是安全的。我编写的可移植代码在不同的构建和执行环境下需要健壮,因此我总是在删除之前检查NULL。 – 2010-05-29 14:26:43

+1

该标准明确规定,当用空指针调用时,delete应该表现正确。如果他们不符合这样一个简单的要求,我会非常害怕我会遇到的其他惊喜,所以我会偏离envs。 – 2010-05-29 16:58:06

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

一定要在你的拆解利用delete要解除obj(并进行解构虚拟如有必要)。

+0

只有构造函数可以有初始化列表。 – 2010-05-29 13:14:48

+0

@In silico,True;我忽略了这一点。抱歉。 – strager 2010-05-29 13:15:46

+0

如果您要使用堆,请确保'obj'管理得当。看到我的答案是如何做到这一点。 – 2010-05-29 13:23:24

0

整点不会让你克隆它。

初始化这样的:Window OBJ

窗口& OBJ = somefunctionConstructingSuchAWindow(其他的构造,而不是复制一个的参数)();

1

如果您的拷贝构造函数是私有的,那么类确实有有拷贝构造函数。看起来你的班级同时拥有私人的ctor和赋值op,这就解释了第二个错误信息。第一个错误信息与您没有显示的WindowHandle类有关。

为了更好地理解这个,我们需要看到Window类 - 例如它是否有默认的构造函数?

+0

http://www.sfml-dev.org/documentation/1.6/classsf_1_1Window.htm#49db47a79ca98b7d65087adeea06e919 – Ockonal 2010-05-29 13:27:04

+0

@Neil:'Window'不需要默认构造。我们需要的唯一要求是其析构函数不会抛出(这当然只有良好的意义)。之后有内存对齐问题等......但是,我们有这样的库;) – 2010-05-29 17:33:40

0

如果Window没有复制构造函数,则不能为其分配Window类的其他对象。您只能使用初始化程序列表从MyClass的构造函数初始化obj。例如:

class MyClass 
{ 
    Window obj; // Hasn't copy constructor 
    public: 
     MyClass() 
      : obj(/*constructor params*/) 
     { 
      /*...*/ 
     } 
} 
0

类成员的初始化应该在类的构造函数来完成像下面的例子:

class MyClass 
{ 
public: 
    MyClass(/* constructor params */); 

private: 
    Window m_obj; // Hasn't copy constructor 
}; 

MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */) 
{ 
} 
0

我想我会得到彻底的是丢弃(读,直到临睡前所有烟)结束,但......假设窗的构造函数不会抛出:

void MyClass::init() 
{ 
    obj::~Window();   // destroy the object 
    new (&obj) Window(...); // construct the object 
}; 

我当然强调不扔对构造函数的要求就好像它抛出一样,你会留下一个非常泥泞的情况: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状态,这是完全可行的,因此您不必担心未定义的行为。

所以基本上就像有不同之处在于神奇的是,对象没有动态分配,从而保证同样的表演智能指针拥有一个动态分配的对象......“正常的”对象:)

我应该补充说,不可复制的障碍是InPlaceFactory创建背后的原因之一。