Polymorphism via Inheritance not working as planned

J

joe

I expected this to work:

class Base
{
virtual void go(int *) {cout<<"BASE CLASS"<<endl;}
};

class Derived : public Base
{
template<typename T>
void go(T*) {cout<<"Derived Class"<<endl;}

};

int main(){
Base *b = new Derived;
b->go(new int[30]);
}

I get "BASE CLASS". I expected the virtual function to work and find
the derived class function.

What's the nitty gritty here of what's going on?
 
V

Victor Bazarov

joe said:
I expected this to work:

On what grounds?
class Base
{
virtual void go(int *) {cout<<"BASE CLASS"<<endl;}
};

class Derived : public Base
{
template<typename T>
void go(T*) {cout<<"Derived Class"<<endl;}

Here is a possible problem: a member template cannot be virtual.
So, even if 'T' *is* 'int', you're not going to achieve making the
instantiation of that template the final overrider to 'Base::go'.
};

int main(){
Base *b = new Derived;
b->go(new int[30]);
}

I get "BASE CLASS". I expected the virtual function to work and find
the derived class function.

Why? The derived class' member is not the overrider for the base's one.
What's the nitty gritty here of what's going on?

When you call 'go', how should the compiler know you're trying to call
the template? If you were allowed to make 'Derived::go' virtual, how
many virtual functions would 'Derived' have?

V
 
N

Noah Roberts

joe said:
I expected this to work:

class Base
{
virtual void go(int *) {cout<<"BASE CLASS"<<endl;}
};

class Derived : public Base
{
template<typename T>
void go(T*) {cout<<"Derived Class"<<endl;}

};

int main(){
Base *b = new Derived;
b->go(new int[30]);
}

I get "BASE CLASS". I expected the virtual function to work and find
the derived class function.

What's the nitty gritty here of what's going on?

Name resolution is performed statically (during compile time).
Derived::go does not override Base::go, it hides it (actually in this
case you might get a compilation error if it is ever instantiated for
int*). However, since you are calling through a pointer to Base,
Base::go is in scope and is resolved. As there is no Derived::go that
overrides Base::go the pointer in the table is to Derived::go and that
is what is called. No instance of the Derived::go template function is
created as it is never called; such instantiation can only occur
statically and cannot be virtual.
 
N

Noah Roberts

Noah said:
Derived::go does not override Base::go, it hides it (actually in this
case you might get a compilation error if it is ever instantiated for
int*).

At least on VC++ 7 it hides the definition of Base::go in Derived even
when the template type is exactly the same as the virtual function.
When you call go through a Derived pointer it calls Derived::go<int>,
when you call from a Base pointer it calls Base::go. This might very
well be undefined behavior though and so it working doesn't really mean
much unless someone more familiar with the standard can say what is
what.
 
V

Victor Bazarov

Noah said:
At least on VC++ 7 it hides the definition of Base::go in Derived even
when the template type is exactly the same as the virtual function.
When you call go through a Derived pointer it calls Derived::go<int>,
when you call from a Base pointer it calls Base::go. This might very
well be undefined behavior though and so it working doesn't really
mean much unless someone more familiar with the standard can say what
is what.

It's not undefined. 14.5.2/4 simply says that a specialisation of
a member function template does not override a virtual function from
a base class. So, if it doesn't override, it must be hiding it.
You can bring in the Base::go (by declaring it), and then they both
will coexist peacefully, and to call the template for a Derived object
you'd need to supply the template argument list.

V
 
N

Noah Roberts

joe said:
I expected this to work:

class Base
{
virtual void go(int *) {cout<<"BASE CLASS"<<endl;}
};

class Derived : public Base
{
template<typename T>
void go(T*) {cout<<"Derived Class"<<endl;}

};

int main(){
Base *b = new Derived;
b->go(new int[30]);
}

I get "BASE CLASS". I expected the virtual function to work and find
the derived class function.

What's the nitty gritty here of what's going on?

Now, on the other hand, the following will do what you expect:

template<typename T>
class Derived : public Base
{
void go(T*) { cout << "DERIVED" << endl; }
};

int main()
{
Base * b = new Derived<int>;
b->go();
}

This is because class templates are a different story. Instantiation
also links up virtual functions to implementations in the derived class.
 

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

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top