James McNellis' answer that "You can't call echo()
from the constructor of Foo<T>
" is almost correct.
You can't call it virtually from a Foo<T>
constructor, because while the body of the Foo<T>
constructor executes the object is of type Foo<T>
. There's no derived class part yet. And a virtual call of echo()
, as in your code, then goes to pure virtual function: bang, dead.
However, you can provide an implementation of a pure virtual function like echo()
, and then call it non-virtually, like Foo::echo()
, from the Foo
constructor. :-) Except that that calls the Foo
implementation. While it seems you'd like to call the derived class' implementation.
Now regarding your problem:
"I'd really like that function in the
constructor."
Well, as I'm writing this your (invalid) code looks like this:
template <typename T> class Foo
{
public:
Foo(T a)
{
x = a;
echo();
}
protected:
T x;
virtual void echo() = 0;
};
class Bar : public Foo<int>
{
public:
Bar(int a) : Foo<int>(a)
{
}
void echo();
};
void Bar::echo()
{
cout << "value: " << x << endl;
}
int main(int argc, char* argv[])
{
Bar bar(100);
return 0;
}
And as far as I understand your problem description, you want the Foo
constructor to call the echo
implementation of whatever class it is that inherits from Foo
.
There are a number of ways to do that; they're all about bringing knowledge of the derived class' implementation to the base class.
One is known as CRTP, the Curiously Recurring Template Pattern, and adapted to your particular problem it can go like this:
#include <iostream>
template< class XType, class Derived >
class Foo
{
public:
Foo( XType const& a )
: state_( a )
{
Derived::echo( state_ );
}
protected:
struct State
{
XType x_;
State( XType const& x ): x_( x ) {}
};
private:
State state_;
};
class Bar
: public Foo< int, Bar >
{
private:
typedef Foo< int, Bar > Base;
public:
Bar( int a ): Base( a ) {}
static void echo( Base::State const& );
};
void Bar::echo( Base::State const& fooState )
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
The above is a solution that isn't bad, but isn't good either. If your actual problem is to call a derived class non-static member function from the base class constructor then the only "good" answer is Java or C#, which let you do such thing. It's intentionally not supported in C++, because it's very easy to then inadvertently try to access as-yet uninitialized stuff in the derived class object.
Anyways, as nearly always, where there is a compile time solution of something, there's also a run time solution.
You can simply pass the function to be executed as a constructor argument, like so:
#include <iostream>
template< class XType >
class Foo
{
protected:
struct State
{
XType x_;
State( XType const& x ): x_( x ) {}
};
public:
Foo( XType const& a, void (*echo)( State const& ) )
: state_( a )
{
echo( state_ );
}
private:
State state_;
};
class Bar
: public Foo< int >
{
private:
typedef Foo< int > Base;
public:
Bar( int a ): Base( a, echo ) {}
static void echo( Base::State const& );
};
void Bar::echo( Base::State const& fooState )
{
using namespace std;
cout << "value: " << fooState.x_ << endl;
}
int main()
{
Bar bar(100);
}
If you study those two programs you'll probably note a subtle difference (in addition to compile time versus run time knowledge transfer).
Finally, there are solutions involving dirty casts and there is also a loophole in the C++ type system that lets you access that protected base class state without casting, by using member pointers. The former is dangerous and latter is obscure and possibly inefficient. So, don't.
But hopefully one of the solutions above will suit you, or some suitable adaption.
Oh, by the way, the more general set of problems that yours seems to be an instance of, is known as DBDI, Dynamic Binding During Initialization. You can find a more general treatment of it in the C++ FAQ item 23.6 Okay, but is there a way to simulate that behavior as if dynamic binding worked on the this object within my base class's constructor?. Also, for the special case where the DBDI is that you want a part of the base class construction to be controlled/supplied by the derived class, see my blog entry "How to avoid post-construction by using Parts Factories".
Cheers & hth.,