How to call a constructor from a constructor

P

PengYu.UT

Hi,

I have the following class. I want the constructor gnuplot_2d(int size)
has the same behavior as if I call from the 2-argument constructor
gnuplot_2d(size, size). But the following definition doesn't work. Do
you have any idea?

Although I can define
template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size) : _size_x(size),_size_y(size){
}
, it will be cumbersome if there are a lot of code in the function
body.

Best wishes,
Peng

template <typename __Tp>
class gnuplot_2d {
public:
gnuplot_2d(int size);
gnuplot_2d(int size_x, int size_y);
~gnuplot_2d(){};
private:
int _size_x;
int _size_y;
};

template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size) : gnuplot_2d<__Tp>(size, size){
}

template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size_x, int size_y) :
_size_x(size_x),_size_y(size_y){
}
 
L

Larry I Smith

Hi,

I have the following class. I want the constructor gnuplot_2d(int size)
has the same behavior as if I call from the 2-argument constructor
gnuplot_2d(size, size). But the following definition doesn't work. Do
you have any idea?

Although I can define
template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size) : _size_x(size),_size_y(size){
}
, it will be cumbersome if there are a lot of code in the function
body.

Best wishes,
Peng

template <typename __Tp>
class gnuplot_2d {
public:
gnuplot_2d(int size);
gnuplot_2d(int size_x, int size_y);
~gnuplot_2d(){};
private:
int _size_x;
int _size_y;
};

template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size) : gnuplot_2d<__Tp>(size, size){
}

template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size_x, int size_y) :
_size_x(size_x),_size_y(size_y){
}

Why not just do the following, or is there more to the
problem than you have stated?

template <typename __Tp>
gnuplot_2d<__Tp>::gnuplot_2d(int size) :
_size_x(size), _size_y(size){
}


Regards,
Larry
 
P

PengYu.UT

As I said in the first message, suppose there are a long chunk of code
in the body of the definition of gnuplot_2d<__Tp>::gnuplot_2d(int
size_x, int size_y), you have to copy all the same code to the
definition of gnuplot_2d<__Tp>::gnuplot_2d(int size).

If you do that you create some problem to maintain the code. Suppose
later on you change the definition of gnuplot_2d(int size_x, int
size_y) a little bit, you have to change the definition of
nuplot_2d(int size) manually to make sure consistency.

I want a better solution to this problem. Thanks!

Best wishes,
Peng
 
L

Larry I Smith

As I said in the first message, suppose there are a long chunk of code
in the body of the definition of gnuplot_2d<__Tp>::gnuplot_2d(int
size_x, int size_y), you have to copy all the same code to the
definition of gnuplot_2d<__Tp>::gnuplot_2d(int size).

If you do that you create some problem to maintain the code. Suppose
later on you change the definition of gnuplot_2d(int size_x, int
size_y) a little bit, you have to change the definition of
nuplot_2d(int size) manually to make sure consistency.

I want a better solution to this problem. Thanks!

Best wishes,
Peng

If the constructors are complex, one approach is to factor
out the code common to all of the constructors (and often
the assignment operator) into a private function that each
of the constructors calls. Here's an incomplete example:

class A
{
public:
A() { doinit(0, 0); }
A(int x) { doinit(x, x); }
A(int x, int y) { doinit(x, y); }
private: // or protected
void doinit(int x, int y)
{
/* does complex stuff used by all constructors */
}
};

Regards,
Larry
 
P

PengYu.UT

So call a constructor from another constructor is impossible, right?

Thanks,
Peng
 
A

Alf P. Steinbach

* (e-mail address removed):
So call a constructor from another constructor is impossible, right?

The question seems to have some invalid assumptions, i.e., meaningless.

To call a constructor of class T on an object being constructed you'll have
to do use very dirty techniques and you'll be throwing overboard all the help
that the language normally gives you, just like when using a void* pointer;
it's not a good idea.

One clean solution to your problem is, instead,

template <typename Tp>
class gnuplot_2d_impl
{
gnuplot_2d_impl( int width, int height )
:
myWidth( width ), myHeight( myHeight )
{
// Lots of code here.
}
};

template <typename Tp>
class gnuplot_2d: private gnuplot_2d_impl
{
gnuplot_2d( int size ): gnuplot_2d_impl( size, size )
{}

gnuplot_2d( int width, int height ): gnuplot_2d_impl( width, height )
{}
};

Here the constructor calls are via the mechanism that C++ offers for calling
constructors from constructors: constructor initalizer lists.

Btw., note that two successive underscores are not allowed in C++ identifiers.

Neither is an underscore followed by an uppercase letter.
 
R

Ron Natalie

So call a constructor from another constructor is impossible, right?
You can't call constructors period. They are automatically invoked
for you as part of object creation. Other than the overloading choices
there isn't much you can do to affect their use.

As we've told you before, put the common code in a member function that
you CAN call.
 
C

cadull

As I said in the first message, suppose there are a long chunk of code
in the body of the definition of gnuplot_2d<__Tp>::gnuplot_2d(int
size_x, int size_y), you have to copy all the same code to the
definition of gnuplot_2d<__Tp>::gnuplot_2d(int size).

If you do that you create some problem to maintain the code. Suppose
later on you change the definition of gnuplot_2d(int size_x, int
size_y) a little bit, you have to change the definition of
nuplot_2d(int size) manually to make sure consistency.

I want a better solution to this problem. Thanks!

You can use placement new. For example:

class N
{
public:
N(int a, int b) : x(a), y(b) {};
N(int c) { new (this) N(c, c); };
N() { new (this) N(0); };

int x, y;
};

vc7.1 optimises these equivalent to writing:

class N
{
public:
N(int a, int b) : x(a), y(b) {};
N(int c) { if(this) { x = c; y = c; }; };
N() { if(this) { x = 0; y = 0; }; };

int x, y;
};

You might be able to eliminate the if statments by writing your own
placement new operator.

Regards,
cadull
 
G

Ganesh

But, if you are using the above approach, i.e placement new, be sure to
call desturctor explicitely.

But here , there are two ways by which class can get generated, one
that uses placement new and one that does not. In one case u need to
call dtor explicitely and the other case you need not.

But, calling the dtor explicitely in both the cases may be harm less as
we really can not know (with out a ugly global/member varibale) how the
object got created at first place
 
M

msalters

(e-mail address removed) schreef:
As I said in the first message, suppose there are a long chunk of code
in the body of the definition of gnuplot_2d<__Tp>::gnuplot_2d(int
size_x, int size_y), you have to copy all the same code to the
definition of gnuplot_2d<__Tp>::gnuplot_2d(int size).

If you do that you create some problem to maintain the code. Suppose
later on you change the definition of gnuplot_2d(int size_x, int
size_y) a little bit, you have to change the definition of
nuplot_2d(int size) manually to make sure consistency.

class C {
C(int ,int) { ... long ... }
C (int size) /* minimal initialization here */
{
C tmp(size,size);
this->swap(tmp);
}
};

The "overhead" is another C object during construction, which is
only minimally initialized. I.e. empty strings etc etc. This minimal
object is then destroyed by tmp's dtor.

HTH,
Michiel Salters
 

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