"Stefan Nikolaus" <st*************@o2online.dewrote in message
news:11**********************@75g2000cwc.googlegro ups.com
Hello,
I've run into problems with defining a template, which inherits from a
base template and the usage of virtual methods in those. I want to
initialize a member variable depending on which template is created
and I tried to define a virtual method, that's called from the base
template ctor. Here's my example code:
#include <iostream>
using namespace std;
template<typename T>
class A
{
public:
A() { cout << "A()" << endl; c = create(); }
virtual ~A() {}
class C
{
public:
virtual ~C() {}
virtual void foo() { cout << "A::C:foo()" << endl; }
};
virtual C* create() { cout << "A::create()" << endl; return new C;
}
C* c;
};
template<typename T>
class B : public A<T>
{
public:
B() : A<T>() { cout << "B()" << endl; }
virtual ~B() {}
class C : virtual public A<T>::C
{
public:
virtual ~C() {}
virtual void foo() { cout << "B::C:foo()" << endl; }
};
virtual typename A<T>::C* create() { cout << "B::create()" << endl;
return new C; }
};
int main( int /*argc*/, char** /*argv*/ )
{
A<inta;
a.c->foo();
B<intb;
b.c->foo();
}
Compiling this with gcc 4.1.0 and running it gives me:
A()
A::create()
A::C:foo()
A()
A::create()
B()
A::C:foo()
I've expected, that B::create() will be called on instantiating
B<int>.
Why is this not the case?
create() is only called in A's constructor, so A::create() is called. Base
classes are always created before derived classes, so B doesn't exist at the
time A's constructor is called, making the virtual function call mechanism
inoperative.
http://www.parashift.com/c++-faq-lit....html#faq-23.5
Your code leaks memory, by the way, since the A::C object is never deleted.
How do I achieve what I want, preferably by using virtual methods?
As indicated above, you should not be using virtual methods in a
constructor.
Various approaches are described here
http://www.parashift.com/c++-faq-lit....html#faq-23.6
As an alterative, you can let the derived class call a constructor in the
base class that does the right initialisation. Try this:
#include <iostream>
#include <memory>
using namespace std;
template<typename T>
class A
{
// constructor to be called by derived class
protected:
// forward declaration
class C;
A(C * pDerivedC) : c(pDerivedC)
{
cout << "A(C * pDerivedC)" << endl;
}
public:
// constructor for an A object by itself
A() : c(create()) // calls A's create
{
cout << "A()" << endl;
}
virtual ~A() {}
class C
{
public:
virtual ~C() {}
virtual void foo() { cout << "A::C:foo()" << endl; }
};
C* create()
{
cout << "A::create()" << endl;
return new C;
}
auto_ptr<Cc;
};
template<typename T>
class B : virtual public A<T>
{
public:
B() : A<T>(create()) // calls B's create
{
cout << "B()" << endl;
}
virtual ~B() {}
class C : public A<T>::C
{
public:
virtual ~C() {}
virtual void foo() { cout << "B::C:foo()" << endl; }
};
C* create()
{
cout << "B::create()" << endl;
return new C;
}
};
int main( int /*argc*/, char** /*argv*/ )
{
A<inta;
a.c->foo();
B<intb;
b.c->foo();
}
--
John Carson