2

Watch the following example:

class A {
public:
    A(int param1, int param2, int param3) {
        // ...
    }
};

class B : public A {
public:
    B() : m_param1(1), m_param(2), m_param(3), A(m_param1, m_param2, m_param3) {
        // ...
    }
};

B b;

Obviously, when "b" will be created, A's ctor will be called before the parameters of B will be initialized.

This rule prevents me from creating "wrapper" classes which simplify the class's initialization.

What is the "right way" for doing it?

Thanks, Amir

PS: In my particular case, the parameters are not primitives, this example just helped me to explain myself.

Amir
  • 349
  • 6
  • 13
  • I understand the problem. However, this looks like you're duplicating information. Why would you be in a situation where you need to initialise both `A` and `B` with the same parameters? – Oliver Charlesworth Nov 14 '10 at 21:14
  • Specifically, I'm using the "Bullet" physics library, which takes pointers to objects as parameters. I want to create and store an object in the child class and pass it's pointer to the superclass. By that I can create a Character class which inherits from library's "physical object" class. – Amir Nov 14 '10 at 21:21
  • i'm not sure i'm getting the question, but remember one thing - statements in the initializing list do not execute in the order you give, they're executed in the order base classes and member variables are given in class declaration. – Janusz Lenar Nov 14 '10 at 21:41
  • ...and that's why Moo-Juice's answer rox :] – Janusz Lenar Nov 14 '10 at 22:14
  • you can pass the base a pointer to a member of the child which has not yet been initialized, there's just not a lot you can do with that pointer prior to initialization (for instance, you can't cast it to a pointer to one of its base classes). 3.8/5 in the standard specifies this. – Steve Jessop Nov 14 '10 at 22:32

3 Answers3

4

Just call A's constructor:

class B : public A
{
public:
    B() : A(1 ,2, 3)
    {
    }; // eo ctor
}; // eo class B

EDIT:

Just read your comment to your original post. It's important to be clear about these things :) Anyway, this answer still holds true if you want to create new data in B, track it in B, and pass it to A:

class Object
{
private:
    int i;
public:
    Object(int _i) : i(_i){};
};

class A
{
public:
    A(Object* _1, Object* _2, Object* _3)
    {
    };
};

class B : public A
{
private:
    Object* _1;
    Object* _2;
    Object* _3;

public:
    B() : A(_1 = new Object(1), _2 = new Object(2), _3 = new Object(3))
    {
    };
};
Moo-Juice
  • 38,257
  • 10
  • 78
  • 128
  • are you sure `B::_1` etc. won't be nullified after `A(Object*,...)` is called? – Janusz Lenar Nov 14 '10 at 21:44
  • There's no reason why it should, the object (at this point) has been allocated. I tested the above on VS2010 so cannot comment on other compilers. I don't see why it would be an issue. – Moo-Juice Nov 14 '10 at 21:47
  • think of `B():_1(new Object(1)),_2(new Object(2)),_3(new Object(3)),A(_1,_2,_3){}`. this will mess up because of actual executing order. actually, important it just works :] – Janusz Lenar Nov 14 '10 at 21:53
  • @Janusz: It does :) The expressions will be evaluated before A's constructor is called. This allows us to both allocate our objects AND assign them to our members AND pass them to the base class. – Moo-Juice Nov 14 '10 at 22:02
  • yeah, your example rox, really :) now I'm wondering if standard *forbids* compilers from auto-initializing members. here, if compiler's not smart enough, it could nullify _1, _2 and _3 right after calling A's ctor, when it's their time to initialize. are you getting my point? :) – Janusz Lenar Nov 14 '10 at 22:13
  • 2
    Hm. If a member of POD type (which includes all pointers) is not listed in a constructor's mem-initializer list, that member is "not initialized". I guess that allows things like this which assign to them earlier than a mem-initializer would. (But if the member type is a class with constructor, this method won't work, of course.) – aschepler Nov 14 '10 at 22:18
  • 1
    thank you, aschepler. it should be mentioned as long as `std::auto_ptr`s are perfectly reasonable to be used here. – Janusz Lenar Nov 14 '10 at 22:27
2

"The parameters are not primitives". So you have something like this?

class Param { /*...*/ };
class A {
public:
  A(const Param& param1, const Param& param2, const Param& param3);
};

class B : public A {
public:
  B();
private:
  Param m_param1;
  Param m_param2;
  Param m_param3;
};

And you want to pass the members of B to the constructor of A. How about this?

class B_params {
protected:
  B_params(int v1, int v2, int v3);
  Param m_param1;
  Param m_param2;
  Param m_param3;
};
class B : private B_params, public A {
public:
  B();
};

B_params::B_params(int v1, int v2, int v3)
  : m_param1(v1), m_param2(v2), m_param3(v3) {}
B::B() : B_params(1,2,3), A(m_param1, m_param2, m_param3) {}

Just make sure B_params comes before A in the list of B's inherited classes.

aschepler
  • 70,891
  • 9
  • 107
  • 161
  • I've already knew this method, but I prefer not to use multiple inheritance. I'll probably use this method, because I can see any other solution besides that and "Factory" design pattern. I'll just wait a little longer to see if a better solution will come up. – Amir Nov 14 '10 at 21:35
0

Not sure I'm getting your question.

If you just want something that helps you to initialize A with some given parameters, you should use an A constructor with default values:

class A {
public:
    A(int param1 = 1, int param2 = 2, int param3 =3) {
        // ...
    }
};
peoro
  • 25,562
  • 20
  • 98
  • 150