简体   繁体   中英

error: 'A' is an inaccessible base of 'B'

I've a code as follows -

#include <iostream>
#include <string>

class A{
    int a;
    public: virtual void sayHello(){ std::cout << "Hello\n"; }
};

class B : private A{
    std::string name;
  public:
    B(std::string _n): name(_n){}
    void sayName(){std::cout << name << "says hello\n";}
    void sayHello(){sayName();}
};


int main() {
    A *ptr = new B("c++");
    ptr->sayHello();
    return 0;
}

which produces the following compiler output -

Error:

 prog.cpp: In function 'int main()': prog.cpp:20:22: error: 'A' is an inaccessible base of 'B' A *ptr = new B("c++"); ^ 

As previously answered - here , here & here , I know how to solve this issue. By using public inheritence instead of private or protected .

But if I really really want to hide some interface behind the base class, isn't there some other way to do this? Or is it impossible to do so according to c++ lang specification.

If you want polymorphic pointer conversion to work outside the class, then the inheritance must be public. There is no way to work around that.

You could add a member function that does the polymorphic pointer conversion within the class:

class B : private A{
    // ...
public:
    A* getA() {
        return this;
    }
};

Which allows you to do this, while still allowing private inheritance:

B* b_ptr = new B("c++");
A* ptr   = b_ptr->getA();
// ptr   = b_ptr; // only allowed in member functions

I haven't encountered a real world design where this trick would be useful, but suit yourself.


PS. Remember that you should destroy objects that you create. Also do realize that delete ptr has undefined behaviour, unless ~A is virtual.

Even though I find it quite strange to hide the base class and want to cast B to A , you can use for that the operator A*() .
It follows a minimal, working example:

#include <iostream>
#include <string>

class A{
    int a;
public:
    virtual void sayHello(){ std::cout << "Hello\n"; }
};

class B : private A{
    std::string name;
public:
    B(std::string _n): name(_n){}
    operator A*() { return this; }
    void sayName(){std::cout << name << "says hello\n";}
    void sayHello(){sayName();}
};

Now you can use it as:

int main() {
    A *ptr = *(new B("c++"));
    ptr->sayHello();
    return 0;
}

Or even better:

int main() {
    B b{"c++"};
    A *ptr = b;
    ptr->sayHello();
    return 0;
}

Adding the cast to A& is as easy as adding the member method operator A&() defined as return *this; .

There is an unsightly way around this: C style casts. C style casts can cast to inaccessible base classes. This is the one and only case where C style casts can do something that C++ casts can't. From cppreference , when a C style cast (T) foo attempts to perform static_cast<T>(foo) , it can do slightly more than just a static_cast :

[P]ointer or reference to a derived class is additionally allowed to be cast to pointer or reference to unambiguous base class (and vice versa) even if the base class is inaccessible (that is, this cast ignores the private inheritance specifier).

Emphasis added

Thus, you can do this:

int main() {
    A *ptr = (A *) new B("c++");
    ptr->sayHello();
    return 0;
}

This is ugly, and it comes with all the disadvantages of casting and especially of C style casts. But it does work, and it is allowed.

Live on Wandbox

When you want to hide that A is a base of B this is valid.

But you assignment

A *ptr = new B("c++");

breaks this hiding, because you use an A* . So c++ generates an error because the dependency is hidden. You can do

B *ptr = new B("c++");

though.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM