Member Objects based on templated classes

D

Dan Huantes

I was presented a problem today where a class had member
variable that was an object of a templated class. The
class wanted to instantiate the object as a private member
variable and call a constructor other than the default
constructor. I couldn't figure out why it wasn't working
so I changed the member variable to a pointer to an object
instead and intialized it in the constructor and destroyed
in the destructor. It bothered me that I had to do this
work around so I generated the small app shown below to
see if I could duplicate the problem and I did. It seems
like you can't have an object that is based on a templated
class call anything other than the default constructor
when created on the stack. I looked in the Stroustrup
book see if there was a reference to this language feature
and couldn't find it. Am I missing something or is my
work around the only way to do this? Thanks!

Dan

P.S.
I compiled this using Visual C++ .Net. I haven't tried it
on 6.0 but it should work(I think...templates sometimes
give 6.0 problems but this is a very simple example)


************Example Follows**********************


// TestApp.cpp : Defines the entry point for the console
application.
//

#include "stdafx.h"

//Templated Class
template <class T>
class DanTest
{
public:
//Default Constructor
DanTest():first(0),second(0){};

//Another Constructor
DanTest(int one, int two):first(one),second(two){};

private:
int first;
int second;

};

//Cleanup the Syntax with typedef
typedef DanTest<double> DanTestD;

//Class with a DanTestD member
class DanTestUser
{
public:

double value;
double value2;
static const int n_const_int = 5;

DanTestUser():value(0.0),value2(0.0){};

private:
//This works fine with the default constructor but
//the compiler throws a C2061 error when I try
//to user the alternate constructor.
//
DanTestD myDT(n_const_int,n_const_int);
};
int _tmain(int argc, _TCHAR* argv[])
{
DanTestUser x;


return 0;
}
 
C

Craig Powers

Dan said:
************Example Follows**********************

// TestApp.cpp : Defines the entry point for the console
application.
//

#include "stdafx.h"

//Templated Class
template <class T>
class DanTest
{
public:
//Default Constructor
DanTest():first(0),second(0){};

//Another Constructor
DanTest(int one, int two):first(one),second(two){};

private:
int first;
int second;

};

//Cleanup the Syntax with typedef
typedef DanTest<double> DanTestD;

//Class with a DanTestD member
class DanTestUser
{
public:

double value;
double value2;
static const int n_const_int = 5;

DanTestUser():value(0.0),value2(0.0){};

private:
//This works fine with the default constructor but
//the compiler throws a C2061 error when I try
//to user the alternate constructor.
//
DanTestD myDT(n_const_int,n_const_int);

This is nonsensical. If you want to initialize a member variable
(with only one limited exception), the place to do it is in the
constructor (preferably, the member initialization list).

Your constructor should read:
DanTestUser() : value(0.0), value2(0.0),
myDT(n_const_int, n_const_int) {}
 
V

Vladimir Petter

That is a terrible mix of Java, C++ and something else :)

See fixed version below.

Vladimir.

//Templated Class
template <class T>
class DanTest
{
public:
//Default Constructor
DanTest():first(0),second(0){};
//Another Constructor
DanTest(int one, int two):first(one),second(two){};
private:
int first;
int second;
};

//Cleanup the Syntax with typedef
typedef DanTest<double> DanTestD;

//Class with a DanTestD member
class DanTestUser
{
public:

double value;
double value2;
static const int n_const_int;

DanTestUser():value(0.0),value2(0.0), myDT(n_const_int, n_const_int) {};

private:
//This works fine with the default constructor but
//the compiler throws a C2061 error when I try
//to user the alternate constructor.
//
DanTestD myDT;
};

const int DanTestUser::n_const_int=5;

int main(int argc, char* argv[])
{
DanTestUser x;
return 0;
}
 
D

Dan Huantes

Thanks! I could have sworn I could do this before but I
checked Visual C++ 6.0 and the compiler complained there
too. I must be losing it. I also tend to lean toward
pointers when it comes to members that are objects. In
that case I would initialize them in the constructor
using 'new'. By the way... what is the "limited
exception"? The only place I can think of is with a COM
CoClass using HRESULT FinalConstruct().

Also... You indicated "preferably the member
initialization list". What's the advantage over just
doing it within the constructor body? Just curious!

Thanks Again!

Dan
 
C

Carl Daniel [VC++ MVP]

Dan said:
Thanks! I could have sworn I could do this before but I
checked Visual C++ 6.0 and the compiler complained there
too. I must be losing it. I also tend to lean toward
pointers when it comes to members that are objects.

A usually useful rule: if a class has virtual functions, store a pointer
(or reference) as the member, and create it using new. If a class doesn't
have virtual functions (which generally behaves it behaves like a "value
type"), then store the member directly rather than a pointer. Of course,
there will always be exceptions to this rule.
In
that case I would initialize them in the constructor
using 'new'. By the way... what is the "limited
exception"? The only place I can think of is with a COM
CoClass using HRESULT FinalConstruct().

The exception would be places where you can't do it in the member
initializer - e.g. where it must be done in another member function and not
the constructor.
Also... You indicated "preferably the member
initialization list". What's the advantage over just
doing it within the constructor body? Just curious!

All members are initialized before the constructor body is entered. If a
member if of class type, then some constructor for that member will run
before the constructor body is entered. In the body, you'll use assignment
to define the value of the member, which generally results in at least one
more constructor call followed by a call to the assignment operator. For
simple members like int's there's no significant difference (and indeed, in
most cases, no difference even at the machine language level), but for
members of class type, using the member-initializer list can be
significantly more efficient.

Further, if you have a member of a const-qualified type, or a member that's
a reference type, or a member of class type with no default constructor,
then the member initializer is the only place where you can initialize it.
It's best to just always use the member initializer list unless there's a
really good reason not to.

-cd
 
C

Craig Powers

Dan said:
Thanks! I could have sworn I could do this before but I
checked Visual C++ 6.0 and the compiler complained there
too. I must be losing it. I also tend to lean toward
pointers when it comes to members that are objects. In
that case I would initialize them in the constructor
using 'new'. By the way... what is the "limited
exception"? The only place I can think of is with a COM
CoClass using HRESULT FinalConstruct().

The one I had in mind was the one that you had already used in the
class - initialization of a static const integral type at the point of
declaration, but obviously yours and Carl's work as well (but aren't
quite the sort of initialization I was thinking of when I wrote the
sentence).
 

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

Top