2

I have a program

#include <iostream>

struct A {
    virtual char f() = 0;
};

struct B {
    virtual char f() = 0;
};

struct Derived : A, B {
public:
    char A::f() override { return CA; }
    char B::f() override { return CB; }

    const char CA = 'A';
    const char CB = 'B';
};

int main(int argc, char** argv)
{
    Derived d;

    A& a = d;

    printf("%c", a.f());

    return 0;
}

It works fine. But when I define A::f outside of the declaration, I have an error.

struct Derived : A, B {
public:
    char A::f() override;
    char B::f() override { return CB; }

    const char CA = 'A';
    const char CB = 'B';
};

char Derived::A::f() { return CA; } //error C2509: 'f': member function not declared in 'Derived'

My question is how to refer correctly to A::f in the definition?

5
  • 2
    The first code doesn't work either. Commented Apr 11 at 12:09
  • @Someprogrammerdude interestingly, unlike gcc and clang, MSVC accepts it. See demo. Commented Apr 11 at 12:14
  • 1
    Why #include <iostream> and then not use anything from it but instead use stuff declared in <cstdio>? Commented Apr 11 at 12:21
  • My question is how to refer correctly to A::f in the definition? If the functions need to be independent, the most expedient solution is to either change the name of A::f, or change the name of B::f. Commented Apr 11 at 12:46
  • 1
    Only MSVC is happy with first version of your code: godbolt.org/z/E1exoMYY1 Commented Apr 11 at 14:18

1 Answer 1

2

You can't do that:

char A::f() override { return CA; }     
char B::f() override { return CB; }

Because you are defining 2 methods with the exact same signature and name. Also, you can't have qualified id(like Class::memberName) in the definition of a method in your class (except for very old version of C++)

If your intend is to call both parent method, you'll need to define a new method for this, like this:

struct C : public A, B 
{
    // This method is implementing both A and B's f method 
    char f() override { return 'C'; }
    // If neither A::f or B::f was pure, you'd write this:
    char fA() { return A::f(); }
    char fB() { return B::f(); }
}; 

For external definition, you'll write the usual, since there's no "base" source of the method in the definition:

char C::f() { return 'C'; }

EDIT: If you intend is to have different implementation for f method depending upon this being a A* or a B*, then you can do this:

struct CState
{
    // Some members you had in C initially
    int someState = 0;
}; 

struct ChildA : A, virtual CState 
{
    char f() override { someState = 1; return 'A'; }
};

struct ChildB : B, virtual CState
{
    char f() override { someState = 2; return 'B'; }
};

struct BothChild : public ChildA, public ChildB
{
};

struct C
{
    operator A&() { return (ChildA&)m; }
    operator B&() { return (ChildB&)m; }
    BothChild m; 
};

// Usage
int main()
{
    C c;
    A & a = c;
    B & b = c;
    printf("A: %c, B: %c\n", a.f(), b.f());
    printf("State: %d (either 1 or 2 depending on argument evaluation order)\n", c.m.someState);
}
Sign up to request clarification or add additional context in comments.

8 Comments

The "exact same name" is usually not a problem as long as they take different parameters and/or have different cv-qualifications (in this case, they don't though). The main issue is the forbidden qualified-ids (A::f and B::f) in the declaration of the member functions - so even if the base class functions had different names, fA and fB, it's illegal to declare the overridden functions char A::fA(); and char B::fB();
Now I've understood that my question had risen from a wrong intention. I was going to use the Derived object as an A instance in one place and as an instance of B in the other place. But the C++ standard doesn't know my intentions and someone may want to use it as an object of type Derived and then the call d.f() will be ambiguous.
If you need A interface in one place and B interface in another, you'll need to add a A & getA() { return (A*)this; } (resp B) and use than instead. They'll both call the same (and unique f method). If you need different implementation for f, you can't do that with a multiple inheritance, you'll have to implement both derived class independently and create a C class with composition instead (with a ChildA a and a ChildB b) member.
@TedLyngmo: You're right. I meant the exact same signature as you said. You can declare char C::A::f() {} outside the class, but you are actually declaring A::f pure virtual method instead when you write that and it's confusing.
@Dmitry: See edit for example implementation or this code
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.