繁体   English   中英

错误:'A'是'B'无法访问的基础

[英]error: 'A' is an inaccessible base of 'B'

我的代码如下 -

#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++"); ^ 

如前所述 - 这里这里这里 ,我知道如何解决这个问题。 通过使用public继承而不是privateprotected

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

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

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

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是虚拟的。

即使我发现隐藏基类并想要将BA也很奇怪,你可以使用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;

这有一个难看的方式: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型铸造。 但它确实有效,而且是允许的。

住在Wandbox上

当你想隐藏AB的基数时,这是有效的。

但是你的任务

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

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

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

虽然。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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