8

Have code as below

// A has a virtual function F().
class A
{
public:
    virtual void F() {};
};

// The same for B.
class B
{
public:
    virtual void F() {};
};

// C inherits A and B.
class C : public A, public B
{
public:
    // How to implement the 2 virtual functions with the same name but from
    // different base classes.
    virtual F() {...}
};

Note that there is a default implementation of F() in the base classes.

Thanks to Jan Herrmann and Spook. Is the below a simpler solution if we have to use some extra helpers?

#include <iostream>

// A has a virtual function F().
class A
{
private:
    virtual void A_F() {}

public:
    void F() {return A_F();};
};

// The same for B.
class B
{
private:
    virtual void B_F() {}

public:
    void F() {return B_F();};
};

// C inherits A and B.
class C : public A, public B
{
private:
    virtual void A_F() {std::cout << "for A\n";}
    virtual void B_F() {std::cout << "for B\n";}

};

int main()
{
    C c;
    c.A::F();
    c.B::F();
    return 0;
}
BenMorel
  • 34,448
  • 50
  • 182
  • 322
user1899020
  • 13,167
  • 21
  • 79
  • 154

2 Answers2

5
class C_a 
  : public A
{
  virtual void F_A() = 0;
  virtual void F() { this->F_A() };
};

class C_b
  : public B
{
  virtual void F_B() = 0;
  virtual void F() { this->F_B() };
};

class C
  : public C_a
  , public C_b
{
  void F_A() { ... }
  void F_B() { ... }
};

If I'm remembing right the ISO committee thought about this problem and discussed a change of the language. But then ... somebody found this nice way to solve this problem :-)

Your second solution is better in case your are able to change your class hierarchy. You may have a lock at http://www.gotw.ca/publications/mill18.htm for a description why it is better.

Jan Herrmann
  • 2,717
  • 17
  • 21
  • This is a smart way. However, concerning maintenance cost in large project, it is not a very good way. It needs changing names of virtual functions of existing code. – user1899020 Feb 07 '13 at 15:35
  • 2
    @user1899020 But I think the only way. Look at http://stackoverflow.com/a/7320055/1918154 it is an answer to a simular question from an expert. – Jan Herrmann Feb 07 '13 at 15:44
  • I understood the OP as wanting to implement both overrides "with the same name"... – Kerrek SB Feb 07 '13 at 16:53
2

Try this:

#include <cstdio>

class A
{
public:
    virtual void F() = 0;
};

class B
{
public:
    virtual void F() = 0;
};

class C : public A, public B
{
    void A::F()
    {
        printf("A::F called!\n");
    }

    void B::F()
    {
        printf("B::F called!\n");
    }
};

int main(int argc, char * argv[])
{
    C c;
    ((A*)(&c))->F();
    ((B*)(&c))->F();

    getchar();

    return 0;
}

Take into consideration though, that you won't be able to call F from C's instance (ambiguous call).

Also, F has to be abstract in A and B, otherwise you'll get compilation error:

Error 1 error C3240: 'F' : must be a non-overloaded abstract member function of 'A'
Spook
  • 25,318
  • 18
  • 90
  • 167
  • To call either `F` on `c`, use `c.A::F()`, `c.B::F()` instead of the cast. See http://stackoverflow.com/questions/6845854/c-multiple-inheritance-function-call-ambiguity?rq=1 – ecatmur Feb 07 '13 at 15:22
  • @ecatmur: The cast is to call the function via that particular interface, rather than to invoke the base-class behaviour from a derived object. – johnsyweb Feb 07 '13 at 15:25
  • Good to know that - though the cast is also valid (I assumed, that c will be passed as a `A*` or `B*` to other function or method). – Spook Feb 07 '13 at 15:25
  • @Spook: With which compilers does this build? – johnsyweb Feb 07 '13 at 15:25
  • @Johnsyweb I used Visual Studio 2012. – Spook Feb 07 '13 at 15:26
  • @ecatmur c.A::F() doesn't work on VS2010. Cannot figure out the reason. Spook, can you try c.A::F() and c.B::F() in your code? Thanks. – user1899020 Feb 07 '13 at 15:28
  • clang v4.0 reports "error: non-friend class member 'F' cannot have a qualified name". – johnsyweb Feb 07 '13 at 15:30
  • 1
    @user1899020 I got: `Error LNK2019: unresolved external symbol "public: virtual void __thiscall A::F(void)" (?F@A@@UAEXXZ) referenced in function _main`. – Spook Feb 07 '13 at 15:39
  • I don't think this answer makes a lot of sense, either :-( – Kerrek SB Feb 07 '13 at 16:55