By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
449,132 Members | 1,352 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 449,132 IT Pros & Developers. It's quick & easy.

Templates and virtual methods

P: n/a
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?
How do I achieve what I want, preferably by using virtual methods?

Regards,
Stefan

Aug 11 '06 #1
Share this Question
Share on Google+
4 Replies


P: n/a
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>.
I don't have the answer for this, but here's a bit simpler example:

#include <iostream>

class Base
{
public:
Base()
{ this->fn(); }

virtual void fn()
{ std::cout<<"Base::fn()"<<std::endl; }
};

class Derived : public Base
{
public:
Derived() { }

void fn()
{ std::cout<<"Derived::fn()"<<std::endl; }
};

int main()
{
Base* b = new Derived;
return 0;
}

I guess somebody will come up with a quotation from the standard on why
this works this way..

Aug 11 '06 #2

P: n/a
Stefan Nikolaus schrieb:
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?
How do I achieve what I want, preferably by using virtual methods?
Read this:
http://www.artima.com/cppsource/nevercall.html

/S
--
Stefan Naewe
stefan_DOT_naewe_AT_atlas_DOT_de
Aug 11 '06 #3

P: n/a
Stefan Nwe wrote:
Read this:
http://www.artima.com/cppsource/nevercall.html
Oops, it's not even template related. It neither works with simple
class inheritance. :-(

Okay, thanks for the pointer.

Regards,
Stefan

Aug 11 '06 #4

P: n/a
"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
Aug 11 '06 #5

This discussion thread is closed

Replies have been disabled for this discussion.