multiple inheritance ambiguity that I can't resolve

G'day all,

I have a situation with some libraries I am using whereby there is an ambiguity with the function to be called due to multiple inheritance and namespaces. The following (very contrived) example shows it. In C::c(), I want to call the f() from N1::B, but I can't work out how to do it. Gcc repoprts the following errors for my three attempts at making the call. Clang reports very similar errors. Does anybody have any ideas on how to do it please?

Thanks,
Graham
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
namespace N1
{
class B
{
protected:
    void f();
};
}

namespace N2
{
class B
{
protected:
    void f();
};
}

class B1 : public N1::B, public N2::B
{
};

class B2 : public N1::B, public N2::B
{
};

class C : public B1, public B2
{
    void c();
};

void
C::c()
{
    N1::B::f();
    B1::N1::B::f();
    static_cast<B1*>(this)->N1::B::f();
}
1
2
3
4
5
z.cpp: In member function âvoid C::c()â:
z.cpp:35: error: cannot call member function âvoid N1::B::f()â without object
z.cpp:36: error: âclass B1::N1â has not been declared
z.cpp:6: error: âvoid N1::B::f()â is protected
z.cpp:37: error: within this context
I think the problem is that your B1 and B2 classes each inherit from N1 and N2's Bs, so there are multiple copies of N1::B and N2::B inside a C object. So when you want to call N1::B::f(), it doesn't know whether to call the one inside of B1 or B2.

Try making the B1 and B2 classes virtually inherit from the namespace classes and see if that changes things.
Nicely contrived.
Any reason virtual inheritance is not used? It would both solve the ambiguity and cut down on the useless copies of the base classes in every instance of B1, B2, or C.

1
2
3
4
5
6
7
8
9
10
11
12
13
class B1 : public virtual N1::B, public virtual N2::B
{
};

class B2 : public virtual N1::B, public virtual N2::B
{
};

void C::c()
{
    N1::B::f();
    N2::B::f();
}



You could resolve this one also by making the desired f() a part of B1's interface for the deriveds

1
2
3
4
5
6
7
8
9
10
class B1 : public N1::B, public N2::B
{
   protected:
    using N1::B::f;
};

void C::c()
{
    B1::f();
}

but that's probably not what you want either.
Last edited on
None of your f()s are static functions but you call them as if they are.
Like I said, the problem is the base classes come from 3rd-party libraries - unfortunately, I have no control over them. So I can't redesign them to do virtual inheritance.

naraku: They aren't static and I'm not calling them as if they are: C derives from them so it can call them like I'm doing.

Thanks for replying, guys.

Any other suggestions?

Graham
What's wrong with this?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

namespace N1 {
class B {
protected:
    void f() { std::cout << "N1::B::f" << std::endl; }
};
} // namespace N1

namespace N2 {
class B {
protected:
    void f() { std::cout << "N2::B::f" << std::endl; }
};
} // namespace N2

class B1 : public N1::B, public N2::B {};
class B2 : public N1::B, public N2::B {};

class B1_ : public B1 { protected: void f() { N1::B::f(); } };

class C : public B1_, public B2 { public: void c() { B1_::f(); } };

int main() { C().c(); }
> the base classes come from 3rd-party libraries - unfortunately, I have no control over them.
> So I can't redesign them to do virtual inheritance.

Use the 'humble interface class' (Stroustrup) to resolve the ambiguity?

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
#include <iostream>

// ************  classes defined by the libray *****************

namespace N1
{
    class B
    {
        public: virtual ~B() {}
        protected: virtual void f()
        { std::cout << "N1::B::f() this: " << this << '\n' ; }
        // ...
    } ;
}

namespace N2
{
    class B
    {
        public: virtual ~B() {}
        protected: virtual void f()
        { std::cout << "N2::B::f() this: " << this << '\n' ; }
        // ...
    } ;
}

class B1 : public N1::B, public N2::B { /* ... */ } ;

class B2 : public N1::B, public N2::B { /* ... */ } ;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ************  interfacew classes defined by us *****************

class B1_ : public B1 // interfacve class to resolve ambiguity
{
    protected:
         virtual void n1_b1_f() { N1::B::f() ; }
         virtual void n2_b1_f() { N2::B::f() ; }
};

class B2_ : public B2 // interfacve class to resolve ambiguity
{
    protected:
         virtual void n1_b2_f() { N1::B::f() ; }
         virtual void n2_b2_f() { N2::B::f() ; }
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// *********  inherit via the interface classes *************

class C : public B1_, public B2_ // inherit from interfacve classes
{
    public: void c()
    {
        n1_b1_f() ;
        n1_b2_f() ;
        n2_b1_f() ;
        n2_b2_f() ;
    }
};

int main()
{
    C cc ;
    cc.c() ;
}
Of course! Thanks very much, m4ster r0shi and JLBorges.

Graham
Topic archived. No new replies allowed.