Calling an overloaded virtual member of a base class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
struct Base1
{
    virtual void Foo( void )
    {
        std::cout << "Base1::Foo( void )\n";
    }

    virtual void Foo( int i )
    {
        std::cout << "Base1::Foo( int = " << i << " )\n";
    }
};

struct Base2
    : public Base1
{
    virtual void Foo( int i )
    {
        std::cout << "Base2::Foo( int = " << i << " )\n";
    }
};

template< class F >
struct CWrapper
    : public F
{
    virtual void Foo( void )
    {
//ERROR - error: no matching function for call to `CWrapper<Base2>::Foo()'
        F::Foo();
    }

    virtual void Foo( int i )
    {
        F::Foo( i );
    }
};


Can anyone tell me if there is a good way to remove the above ERROR while only modifying CWrapper?

EnderJSC
The virtual function call only works through pointers or references to the base class.
When accessed like a normal function (like the way you are attempting it) they behave just like normal functions.

Also templates and the virtual don't mix well.

You can do this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template< class F >
struct CWrapper
    : public F
{
    virtual void Foo( void )
    {

        F::Base1::Foo();//see Note below
    }

    virtual void Foo( int i )
    {
        F::Foo( i );
    }
};


Note:
What I have shown above will only work with the specific example you have posted - CWrapper<Base2> because F::Base1::Foo(); will expand to Base2::Base1::foo().

It wouldn't work with CWrapper<Base1> because F::Base1::Foo(); will expand to Base1::Base1::foo() which is again an error

Right now I can't think of a sensible way to make what you are trying to achieve work.
This is the way I was thinking though:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include <iostream>

using namespace std;

struct Base1
{
    virtual void Foo(  )
    {
        std::cout << "Base1::Foo( void )\n";
    }

    virtual void Foo( int i )
    {
        std::cout << "Base1::Foo( int = " << i << " )\n";
    }
};

struct Base2
    : public Base1
{
    virtual void Foo( int i )
    {
        std::cout << "Base2::Foo( int = " << i << " )\n";
    }
};

template< class Base, class Derived >
struct CWrapper
    //: public Derived //<<Don't think we need this ===
{
    Base* pb;//<<===================

    CWrapper(){pb = new Derived;}//<<=====================
    ~CWrapper (){delete pb;}//<<========================
  
  virtual void Foo(  )
    {
      pb->Foo();
    }

    virtual void Foo( int i )
    {
        pb->Foo( i );
    }
};


//TEST/////////////////
int main()
{

  CWrapper<Base1, Base2> cw;

  cw.Foo();
  cw.Foo(3);
}
Last edited on
Thanks for the response. I had forgotten about the sub class syntax you pointed out
<class>::<baseclass>::<function>()
I didn't go into too much detail about the situation, but your above solution won't work for me, because I need to pass a pointer of type Base1 to an external system, that uses the virtual interface to call my implementation. The thing that I don't understand is that the below code compiles fine.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct Base1
{
    virtual void Foo( void )
    {
        std::cout << "Base1::Foo( void )\n";
    }

    virtual void Foo( int i )
    {
        std::cout << "Base1::Foo( int = " << i << " )\n";
    }
};

struct Base2
    : public Base1
{
//    virtual void Foo( int i )
//    {
//        std::cout << "Base2::Foo( int = " << i << " )\n";
//    }
};

template< class F >
struct CWrapper
    : public F
{
    virtual void Foo( void )
    {
        F::Foo();
    }

    virtual void Foo( int i )
    {
        F::Foo( i );
    }
};


basically because both overloads for Foo are implemented at the same inheritance level. Anyway, thanks again for the help.

EnderJSC
As I hinted in my original post - there is no polymorphism at work here - you are calling the virtual functions
directly e.g F::foo() - this means that they behave like normal functions.

There is something called 'data hiding' - which is basically as follows:
'If a derived class has a function with the same name as one in the base class, the function in the derived class hides ALL the functions in the base class with that name'

Which is why in your original post when when the template parameter F was a Base2 type - we could not
call F::Foo() - because it is hidden by Base2::Foo(int).
We got around this by saying F::Base1::Foo()
There was a similar question to this not too long ago. I can't find the exact thread...

I know you said you don't want to change Base2... but there's a very simple solution to this if you can:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
struct Base1
{
    virtual void Foo(  )
    {
        std::cout << "Base1::Foo( void )\n";
    }

    virtual void Foo( int i )
    {
        std::cout << "Base1::Foo( int = " << i << " )\n";
    }
};

struct Base2
    : public Base1
{
    virtual void Foo( int i )
    {
        std::cout << "Base2::Foo( int = " << i << " )\n";
    }

    using Base1::Foo;  // <=== Problem solved
};
Thank you for the responses. This was exactly what I was looking for. I did understand that Polymorphism was not applied to the call (in fact I was counting on it), but I wasn't fully aware of the 'data hiding' mechanism. I'm not sure I'm clear WHY Foo( void ) hides Foo( int ) (or the other way around), but at least I know that this is an understood thing. I knew that there was some syntax for adding the function signature into the namespace of the deriving class, but couldn't remember it. While it doesn't solve my problem, I feel like at least I have enough information to work around the problem. Thanks again

EnderJSC
Topic archived. No new replies allowed.