Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Diamond of death and Scope resolution operator (c++)

I have this code (diamond problem):

#include <iostream>
using namespace std;

struct Top
{
    void print() { cout << "Top::print()" << endl; }
};

struct Right : Top 
{
    void print() { cout << "Right::print()" << endl; }
};

struct Left : Top 
{
    void print() { cout << "Left::print()" << endl; }
};

struct Bottom: Right, Left{};

int main()
{
    Bottom b;
    b.Right::Top::print();
}

I want to call print() in Top class.

When I try to compile it I get error: 'Top' is an ambiguous base of 'Bottom' on this line: b.Right::Top::print(); Why is it ambiguous? I explicitly specified that I want Top from Right and not from Left.

I don't want to know HOW to do it, yes it can be done with references, virtual inheritance, etc. I just want to know why is b.Right::Top::print(); ambiguous.

like image 453
PcAF Avatar asked Apr 21 '16 20:04

PcAF


People also ask

What is the scope resolution operator in C++?

In C++, scope resolution operator is ::. It is used for following purposes. 1) To access a global variable when there is a local variable with same name: 2) To define a function outside a class.

How to solve diamond problem in C++?

There are two way to solve Diamond Problem; - Using Scope resolution operator - Inherit base class as virtual Calling print function by b.Right::Top::print () should be executed with no errors. But there is still two objects of your base class (Top) referred from your Bottom class.

When to use the unary scope operator?

You can use the unary scope operator if a namespace scope or global scope name is hidden by a particular declaration of an equivalent name during a block or class. For example, if you have a global variable of name my_var and a local variable of name my_var, to access global my_var, you'll need to use the scope resolution operator.


1 Answers

Why is it ambiguous? I explicitly specified that I want Top from Right and not from Left.

That was your intent, but that's not what actually happens. Right::Top::print() explicitly names the member function that you want to call, which is &Top::print. But it does not specify on which subobject of b we are calling that member function on. Your code is equivalent conceptually to:

auto print = &Bottom::Right::Top::print;  // ok
(b.*print)();                             // error

The part that selects print is unambiguous. It's the implicit conversion from b to Top that's ambiguous. You'd have to explicitly disambiguate which direction you're going in, by doing something like:

static_cast<Right&>(b).Top::print();
like image 61
Barry Avatar answered Sep 23 '22 15:09

Barry