calling constructor from constructor

J

jrwats

So at my work, people are morally opposed to default arguments and
prefer function overloading. Put your opinions about that aside for
the moment (because I don't have a choice but to bow down to coding
standard) :)

Problem is if class B inherits from class A, which provides no default
constructor, how can you effectively provide an overloaded
constructor?

This following does not work:
class A {
public:
A(int x) { }
};

class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) { B(x,20); } // error: no matching function for call to
A::A()

};

Neither does this:
class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) : B(x,20) { } // type 'B' is not a direct base of 'B'

};

This following works, but I really do not like it:

class B : A {
public:
B(int x, int y) : A(x), m_nX(x), m_nY(y) { }
B(int x) : A(x), m_nX(x), m_nY(20) { }

int m_nX;
int m_nY;
};

If we want different behavior in the constructor, we have to change it
in both places. Blech!
 
J

jrwats

Just wanted to mention for clarity, that in all examples, B was meant
to have:

int m_nX, m_nY;

members. Also they were meant to have corresponding initialization
lists.
 
D

Daniel Pitts

jrwats said:
So at my work, people are morally opposed to default arguments and
prefer function overloading. Put your opinions about that aside for
the moment (because I don't have a choice but to bow down to coding
standard) :)

Problem is if class B inherits from class A, which provides no default
constructor, how can you effectively provide an overloaded
constructor?

This following does not work:
class A {
public:
A(int x) { }
};

class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) { B(x,20); } // error: no matching function for call to
A::A()

};

Neither does this:
class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) : B(x,20) { } // type 'B' is not a direct base of 'B'

};

This following works, but I really do not like it:

class B : A {
public:
B(int x, int y) : A(x), m_nX(x), m_nY(y) { }
B(int x) : A(x), m_nX(x), m_nY(20) { }

int m_nX;
int m_nY;
};

If we want different behavior in the constructor, we have to change it
in both places. Blech!

externalize the "difference" into a function:

inline B createB(int x, int y) {
return B(x, y);
}

inline B createB(int x) {
return B(x, 20);
}


One down-side to this is that you lose implicit conversion to B from
int, but that may have been a unintentional in your original design and
possibly a good change.
 
A

Alf P. Steinbach

* jrwats:
So at my work, people are morally opposed to default arguments and
prefer function overloading. Put your opinions about that aside for
the moment (because I don't have a choice but to bow down to coding
standard) :)

Problem is if class B inherits from class A, which provides no default
constructor, how can you effectively provide an overloaded
constructor?

This following does not work:
class A {
public:
A(int x) { }
};

class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) { B(x,20); } // error: no matching function for call to
A::A()

};

Neither does this:
class B : A {
public:
B(int x, int y) : A(x) { }
B(int x) : B(x,20) { } // type 'B' is not a direct base of 'B'

};

This following works, but I really do not like it:

class B : A {
public:
B(int x, int y) : A(x), m_nX(x), m_nY(y) { }
B(int x) : A(x), m_nX(x), m_nY(20) { }

int m_nX;
int m_nY;
};

If we want different behavior in the constructor, we have to change it
in both places. Blech!

If you absolutely need to avoid C++ default argument specifications then one
natural solution is to introduce an intermediate class:

class BState: public A
{
private:
int x_;
int y_;
protected:
BState( int x, int y ): A(x), x_( x ), y_( y ) {}
};

class B: public BState
{
public:
B( int x ): BState( x, 20 ) {}
B( int x, int y ): BState( x, y ) {}
};

There's an old saying that every computer science problem can be solved by an
extra layer of indirection.

It's probably not always true, but it's often a good idea to think that way.


Cheers & hth.,

- Alf
 
J

jrwats

If you absolutely need to avoid C++ default argument specifications then one
natural solution is to introduce an intermediate class:

    class BState: public A
    {
    private:
        int x_;
        int y_;
    protected:
        BState( int x, int y ): A(x), x_( x ), y_( y ) {}
    };

    class B: public BState
    {
    public:
        B( int x ): BState( x, 20 ) {}
        B( int x, int y ): BState( x, y ) {}
    };

There's an old saying that every computer science problem can be solved by an
extra layer of indirection.

It's probably not always true, but it's often a good idea to think that way.

Cheers & hth.,

- Alf

This is exactly what I want - assuming code reviewers are OK with a
helper class. Using a B::Init() function to take care of the shared
behavior solves only part of the problem.

Thanks for all the responses!
 
J

James Kanze

* jrwats:

[...]
If you absolutely need to avoid C++ default argument
specifications then one natural solution is to introduce an
intermediate class:

Just a nit, but I fail to see what the problem has to do with
default arguments. Either you can initialize A with no
arguments, or you can't. If you can't, you've got to provide
the necessary arguments somehow. (Your suggestion of an
intermediate class is a good idea. More generally, deriving
from a class is a simple way to provide additional constructors,
if the constructors the class actually provides don't fully
suite your needs, for one reason or another.)
 
A

Alf P. Steinbach

* James Kanze:
* jrwats:
[...]
If we want different behavior in the constructor, we have to
change it in both places. Blech!
If you absolutely need to avoid C++ default argument
specifications then one natural solution is to introduce an
intermediate class:

Just a nit, but I fail to see what the problem has to do with
default arguments.

It's apparently a requirement of the OP's workplace's coding standard that there
be no default arguments. Given the sillyness of that I think it not unlikely
that someone's playing the Dominate & Discredit game with the OP and perhaps
others. And if so then a solution will only be acceptable if, in a context where
the constraint is not known, it sufficiently demonstrates lack of ability and
intelligence, i.e. then the proposed solution here won't be acceptable.


Cheers & hth.,

- Alf
 
F

Fred

So at my work, people are morally opposed to default arguments and
prefer function overloading.  Put your opinions about that aside for
the moment (because I don't have a choice but to bow down to coding
standard) :)

Problem is if class B inherits from class A, which provides no default
constructor, how can you effectively provide an overloaded
constructor?

This following does not work:
class A {
public:
    A(int x) {  }

};

class B : A {
public:
    B(int x, int y) : A(x) {  }
    B(int x) {  B(x,20); } // error: no matching function for call to
A::A()

};

Neither does this:
class B : A {
public:
    B(int x, int y) : A(x) {     }
    B(int x) : B(x,20) {  } // type 'B' is not a direct base of 'B'

};

This following works, but I really do not like it:

class B : A {
public:
    B(int x, int y) : A(x), m_nX(x), m_nY(y) {  }
    B(int x) : A(x), m_nX(x), m_nY(20) { }

    int m_nX;
    int m_nY;

};

If we want different behavior in the constructor, we have to change it
in both places.  Blech!


Just have both of B's constructors invoke the known A constructor,
then call a private initialization function:

class A {
public:
int a;
A(int x);
};


class B : A {
public:
int b;
B(int x, int y) ;
B(int x);
private:
void init(int y);
};


A::A(int x) {
a = x;
}

B::B(int x, int y) :A(x) {
init(y);
}

B::B(int x) : A(x) {
init(20);
}

void B::init(int y) {
b = y;
}
 
J

jrwats

Just have both of B's constructors invoke the known A constructor,
then call a private initialization function:

class A {
   public:
      int a;
      A(int x);

};

class B : A {
    public:
      int b;
      B(int x, int y) ;
      B(int x);
    private:
      void init(int y);

};

A::A(int x) {
   a = x;

}

B::B(int x, int y) :A(x) {
    init(y);

}

B::B(int x) : A(x) {
    init(20);

}

void B::init(int y)  {
    b = y;

}

What about when the member built-in types (ints) are instead classes?
We are losing the efficiency gained from initialization lists. Here's
a better explanation via code with comments - I left the ints because
I'm lazy (sorry), but imagine all the members are a class type:

// Base classes providing no default constructor...
class Base1
{
public:
Base1(int x) : m_nBase1X(x) { }
int m_nBase1X;
};

class Base2
{
public:
Base2(int y) : m_nBase2Y(y) { }
int m_nBase2Y;

};

class BConstructorProxy :
public Base1,
public Base2
{
public:
BConstructorProxy(int x, int y) : Base1(x), Base2(y), m_nX(x), m_nY
(y)
{
CommonInit();
}

protected:
void CommonInit(){ /* Do stuff!*/}
int m_nX, m_nY;
};

class B : public BConstructorProxy {
public:
B(int x, int y) : BConstructorProxy(x, y)
{ }

B(int x) : BConstructorProxy(x, 20)
{ }

B() : BConstructorProxy(20, 20)
{ }
};

// The alternative w/out BConstructorProxy
class C :
public Base1,
public Base2
{
public:
// Imagine changing constructor behavior - yes this is grouped
// into a C::CommonInit function. But what about adding a member
// - or deriving from another Base class? Suppose our "main"
// constructor had instead 5 arguments (rather than 3) and we
// wanted to provide default construction for all other scenarios.
// That's a lot of code reuse...
C(int x, int y) : Base1(x), Base2(y), m_nX(x), m_nY(y)
{
CommonInit();
}

C(int x) : Base1(x), Base2(20), m_nX(x), m_nY(20)
{
CommonInit();
}

C() : Base1(20), Base2(20), m_nX(20), m_nY(20)
{
CommonInit();
}

protected:
void CommonInit(){ /* Do Stuff */ }
int m_nX, m_nY;
};
 
J

Juha Nieminen

jrwats said:
B(int x) : B(x,20) { } // type 'B' is not a direct base of 'B'

You'll have to wait for the next C++ standard to be implemented in
your compiler in order to be able to do that.
 
J

James Kanze

* James Kanze:
* jrwats:
[...]
If we want different behavior in the constructor, we have to
change it in both places. Blech!
If you absolutely need to avoid C++ default argument
specifications then one natural solution is to introduce an
intermediate class:
Just a nit, but I fail to see what the problem has to do
with default arguments.
It's apparently a requirement of the OP's workplace's coding
standard that there be no default arguments. Given the
sillyness of that I think it not unlikely that someone's
playing the Dominate & Discredit game with the OP and perhaps
others. And if so then a solution will only be acceptable if,
in a context where the constraint is not known, it
sufficiently demonstrates lack of ability and intelligence,
i.e. then the proposed solution here won't be acceptable.

I understand that, but I fail to see how default arguments play
a role here. If he can modify the base class, he can just as
easily add a default constructor to as add a default argument to
the existing constructor. If he can't, he can either ensure
that all of the derived class constructors do pass an argument
(which doesn't seem overly constraining), or use your solution.

And of course, if, as seems likely, the people who decide the
rules are playing silly games, who knows what they might accept,
or might not. (Either they're playing silly games, or they're
incompetent. Probably the latter, really: never account to evil
intentions what can be explained by simple stupidity.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top