1
4

7 回答 7

6

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).

于 2010-05-29T13:14:18.323 回答
4

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.

于 2010-05-29T13:14:28.180 回答
1

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?

于 2010-05-29T13:15:21.310 回答
1

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.

于 2010-05-29T17:28:05.523 回答
0

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();

于 2010-05-29T13:15:16.740 回答
0

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*/)
      {
          /*...*/
      }
}
于 2010-05-29T13:17:23.087 回答
0

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 */)
{
}
于 2010-05-29T15:38:54.117 回答