7 回答
Use an initializer list:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass() :
obj(/* constructor params */)
{
}
}
This goes for references, too. You can assign any member variable in an initializer list. It only works in the constructor, though.
If you want it to work outside a constructor, you need to use a pointer:
class MyClass
{
Window *obj;
public:
void init()
{
obj = new Window(/* constructor params */);
}
}
Be sure to deallocate obj
using delete
in your deconstructor (and make the deconstructor virtual if necessary).
Your MyClass
needs a constructor to initialize the obj
member.
class MyClass
{
private:
Window obj;
public:
MyClass() : obj(/* constructor params */) // This is an initializer list
{}
};
If you need the init()
function, and the Window
object provides its own
init()
function of some sort, you can do this:
class MyClass
{
private:
Window obj;
public:
void init()
{
obj.init(/* init params */); // Window's own init() function
}
};
If the Window
class does not have anything like an init()
function, you can use the heap (not recommended unless you absolutely have to):
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;
}
}
};
If the Window
class declares a private copy constructor and/or copy assignment operator, then you cannot assign a new Window
instance to obj
.
If your copy constructor is private the class does have a copy constructor. It seems your class has bothy copy ctor and assignment op as private, which explains the second error message. The first error message has something to do with the WindowHandle class, which you haven't shown.
To make much more sense of this, we'd need to see the Window class too - does it (for example) have a default constructor?
I suppose I'm going to get thoroughly trashed for that (read till the end before going all fuming) but... assuming the constructor of windows never throws:
void MyClass::init()
{
obj::~Window(); // destroy the object
new (&obj) Window(...); // construct the object
};
I shall of course underline the not throw requirement of the constructor as if it throws you'll be left with a very muddy situation: the destructor of MyClass
will call the destructor of Window
regardless of whether or not the object is alive and kicking or trashed because of a failed construction, and in the latter case you get undefined behavior.
Of course, a typical thing will thus be std::unique_ptr<Window>
but we have the hurdle of dynamic allocation where clearly the situation does not mandate it...
So you'd be better off using a library: Boost.Optional.
class MyClass
{
public:
private:
boost::optional<Window> obj;
};
The syntax invocation is similar to a pointer:
obj->foo();
But the one benefit is that you get inplace destruction / construction with safer semantics. Destruction is easy:
// both call ~Window() if an instance had been constructed
obj.reset();
obj = detail::none_t();
For construction use a TypedInPlaceFactory. And for assignment too... which of course clears up the previous instance (if any) first:
void MyClass::init(Arg1 arg1, Arg2 arg2)
{
obj = boost::in_place<Window>(arg1, arg2);
}
The main advantage is that if any exception is now encountered during construction, the optional
object is left in the unitialized
state, which is perfectly viable, and thus you need not fear undefined behavior.
So basically it's like having a dynamically allocated object owned by a smart pointer... except that the magic is that the object is not dynamically allocated, thus guaranteeing the very same performances that a "normal" object :)
I should add that the non-copyable hurdle is one of the reason behind the InPlaceFactory creation.
The whole point is not letting you clone it.
Initialize like this: Window obj(parameters of other constructor, not the copy one)
or
Window &obj = somefunctionConstructingSuchAWindow();
If Window
doesn't have a copy constructor, you cannot assign another object of class Window
to it. You can initialize obj
only from the constructor of MyClass
using an initializer list. For example:
class MyClass
{
Window obj; // Hasn't copy constructor
public:
MyClass()
: obj(/*constructor params*/)
{
/*...*/
}
}
The initialization of class members should be done on class constructor like on the following example:
class MyClass
{
public:
MyClass(/* constructor params */);
private:
Window m_obj; // Hasn't copy constructor
};
MyClass::MyClass(/* constructor params */) : m_obj(/* constructor params */)
{
}