错误:' A'是一个难以接近的基地' B'

时间:2016-09-05 14:13:28

标签: c++ class oop c++11 inheritance

我的代码如下 -

#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;
}

生成以下编译器输出 -

  

错误:

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

如前所述 - herehere&amp; here,我知道如何解决这个问题。使用public继承而不是privateprotected

但是,如果我真的想隐藏基类背后的某些界面,是不是还有其他方法可以做到这一点?或者根据c ++ lang规范不可能这样做。

4 个答案:

答案 0 :(得分:4)

如果您希望多态指针转换在类外部工作,那么继承必须是公共的。没有办法解决这个问题。

您可以添加在类中执行多态指针转换的成员函数:

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

允许您执行此操作,同时仍允许私有继承:

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

我没有遇到真正的世界设计,这个技巧会有用,但适合自己。

PS。请记住,您应该销毁您创建的对象。还要认识到delete ptr具有未定义的行为,除非~A是虚拟的。

答案 1 :(得分:2)

即使我发现隐藏基类并希望将B投射到A也很奇怪,您可以使用operator A*()。 它遵循一个最小的工作示例:

#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();}
};

现在您可以将其用作:

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

甚至更好:

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

将广告投放添加到A&就像添加定义为operator A&()的成员方法return *this;一样简单。

答案 2 :(得分:2)

有一个难看的方式:C风格演员。 C样式转换可以转换为无法访问的基类。这是唯一一种C风格演员可以做C ++演员无法做到的事情。从cppreference开始,当C样式广告(T) foo尝试执行static_cast<T>(foo)时,它可以做的不仅仅是static_cast

  

[p] ointer或对派生类的引用另外允许转换为指针或引用到明确的基类(反之亦然),即使基类是不可访问的(即,这个强制转换会忽略私有继承说明符。

重点增加

因此,您可以这样做:

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

这很丑陋,它带有铸造的所有缺点,特别是C风格的演员表。但它确实有效,而且是允许的。

Live on Wandbox

答案 3 :(得分:0)

如果您想要隐藏AB的基础,那么这是有效的。

但你分配了

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

打破隐藏,因为您使用A*。所以c ++会生成错误,因为依赖项是隐藏的。你可以做到

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

虽然。