tags:

views:

156

answers:

2

I'm not an C++ expert and still do not have a great intuitive grasp of how things works. I think this is a simple question. I am having trouble passing objects with state to other objects. I'd prefer to avoid passing pointers or references, since once the initialized objects are setup, I call them millions of times in a tight loop. I think I'm dong something like a Command pattern. Here's the core of the problem. My header code is something like:

class ObjectWithState {
public:
  ObjectWithState(int state) { // This constructor creates the problem!
    state_ = state;       // everyting works with no constructor.
  }
private:
  int state_;
};

class TakesObject {
public:
  TakesObject(ObjectWithState obj) {
    obj_ = obj;
  }
private:
  ObjectWithState obj_;
};

My main() functions looks like:

int main () {
  ObjectWithState some_object(1);
  TakesObject takes_object(some_object);
  return 0
}

I get the following error (g++):

test.h: In constructor 'TakesObject::TakesObject(ObjectWithState)':
test.h:14: error: no matching function for call to 'ObjectWithState::ObjectWithState()'
test.h:5: note: candidates are: ObjectWithState::ObjectWithState(int)
test.h:3: note:                 ObjectWithState::ObjectWithState(const ObjectWithState&)

Simple answer?

I not sure if this has to do with copy constructors. If so, I'm trying to find a solution that keeps the class definition of ObjectWithState very clean and short. Users of this library will be defining lots of small functions like that which will be used by TakesObject function. Ideally programmers of the ObjectsWithState just need to focus on implementing a simple object. Perhaps I'm going astray...

+5  A: 

What you may want to do is use the member initialisation syntax:

class TakesObject {
public:
  TakesObject(ObjectWithState obj): obj_(obj) {
  }
private:
  ObjectWithState obj_;
};

In your posted code, the TakesObject constructor will first try to construct a new ObjectWithState with its default constructor, then call the assignment operator to copy the passed-in obj to obj_. The above example constructs the obj_ directly using its copy constructor.

You will also need to define a copy constructor for your ObjectWithState class, too:

class ObjectWithState {
public:
  ObjectWithState(int state) {
    state_ = state;
  }
  ObjectWithState(const ObjectWithState &rhs) {
    state_ = rhs.state_;
  }
private:
  int state_;
};

If you omit all constructors from your class declaration, then the compiler supplies a default and a copy constructor for you. If you declare any constructors, then the compiler supplies no default or copy constructor, so you must implement your own.

Greg Hewgill
Good answer, but he doesn't need to declare a copy constructor. The default copy constructor is adequate.
rlbond
He does need to declare the copy constructor - once he declared ObjectWithState(int), the default copy constructor was lost.
Blair Conrad
<code> ObjectWithState() {} ObjectWithState(int state) { state_ = state; }</code>Seems to work. Using the initialization list requires the const constructor too, I think. Any way to simplify the ObjectWithState?
Tristan
A C++ compiler *must* declare an implicit copy constructor if the user doesn't define one. It doesn't matter if the user declares other constructors, it's only the *default* constructor that is not implicitly declared if the user supplies other constructors.
Charles Bailey
+1  A: 

You're getting this error because you're declaring a constructor. The compiler will provide the default constructor only if you don't declare a constructor in your class. Because you have declared a constructor, you don't get the default one. You have to explicitly declare a constructor with no parameters.

jdt141
Okay thanks. I presume there is no better way to do this to avoid having to write all these extra constructors in ObjectwithState? I'd prefer if ObjectWithState had nothing but the essentials. Should I be subclassing and putting a default constructor in the base? And does the `()` constructor need to do anything? Or is it just `ObjectWithState() {}'
Tristan
Unless, of course, he doesn't want a default constructor.
rlbond
@rlbond Greg's solution above is the "more correct" way to do this, IMO. Using the initialization with the constructor. You should always have a copy constructor anyway. You never know who is going to copy your object.
jdt141