6
votes

I have this code:

class Foo
{
public:
    int x = 4;
    int & operator[](size_t index) { return x; }
};

class Bar : protected Foo
{
public: 
    using Foo::operator[];

    Bar () { x++; }
};

int main(int agrc, char ** argv)
{
    typedef int &(Bar::*getOp)(size_t index);

    Bar b;
    auto bVal = b[4];
    getOp o = &Bar::operator[]; 
    auto bVal2 = (b.*o)(7);
}

However, I cannot compile this, because

error C2247: 'Foo' not accessible because 'Bar' uses 'protected' to inherit from 'Foo'

Why is this not possible, when I have used using and I can call operator directly? Is there any way around?

If I change inheritance to public, it is working.

Note: This is just an example of larger class. I dont want to use public inheritance, because I dont want to be able to do Foo f = Bar() because in Bar, I am hiding parent methods (I have not use virtual).

2
FWIW, you can use this method to stop slicing when using public inheritance.NathanOliver
@JoãoPaulo That still wont work. They need (b.*o)(7); or (bVal[some_valid_index].*o)(7);NathanOliver
Whereop is defined?João Paulo
@JoãoPaulo It was typo, sorryMartin Perry

2 Answers

5
votes

Why is this not possible, when I have used using and I can call operator directly?

The using declaration gives you access to the name operator[]. But it doesn't alter the member's type. It stays int &(Foo::*)(size_t). Note the Foo.

So converting to the declared type of o requires a conversion down the inheritance tree. This conversion must check that the target class is indeed derived from the base, but that is an inaccessible base.

One way to work around it is to give Bar a member function that returns that pointer. Inside Bar's scope the base will be accessible to the conversion. Also, this sort of conversion requires a static_cast.

3
votes

This conversion is not allowed once the base class Foo is inaccessible.

Instead of using using Foo::operator[], maybe this can solve your problem:

int& operator[](size_t index) { // now a Bar::operator[], not Foo:: anymore
    return Foo::operator[](index);
}