策略继承和不可访问的受保护成员

ben*_*aug 6 c++ policy inheritance visibility protected

似乎来自模板策略类的受保护成员是不可访问的,即使类层次结构似乎是正确的.

例如,使用以下代码段:

#include <iostream>
using namespace std;

template <class T>
class A {
  protected:
    T value;
    T getValue() { return value; }
  public:
    A(T value) { this->value = value; }
};

template <class T, template <class U> class A>
class B : protected A<T> {
  public:
    B() : A<T>(0) { /* Fake value */ }
    void print(A<T>& input) {
      cout << input.getValue() << endl;
    }
};

int main(int argc, char *argv[]) {
  B<int, A> b;
  A<int> a(42);
  b.print(a);
}
Run Code Online (Sandbox Code Playgroud)

编译器(OS X上的clang,但gcc返回相同类型的错误)返回以下错误:

Untitled.cpp:18:21: error: 'getValue' is a protected member of 'A<int>'
      cout << input.getValue() << endl;
                ^
Untitled.cpp:25:5: note: in instantiation of member function 'B<int, A>::print' requested here
  b.print(a);
    ^
Untitled.cpp:8:7: note: can only access this member on an object of type 'B<int, A>'
    T getValue() { return value; }
      ^
1 error generated.
Run Code Online (Sandbox Code Playgroud)

奇怪的是,编译器的最后一个注释是完全正确的,但已经应用,因为b对象是类型的'B<int, A>'.这是编译器错误还是代码中存在问题?

谢谢

Dav*_*vid 9

您误解了受保护访问的含义.

受保护的成员可以通过派生类调用.但仅限于类本身内包含的基础对象.

例如,如果我简化问题,使用:

class A {
protected:
    void getValue(){}
};

class B : protected A
{
public:
    void print(A& input)
    {
        input.getValue(); //Invallid
    }
};
Run Code Online (Sandbox Code Playgroud)

除了类本身内的"A"对象之外,不能在"A"对象上调用getValue.例如这是有效的.

    void print()
    {
        getValue(); //Valid, calling the base class getValue()
    }
Run Code Online (Sandbox Code Playgroud)

正如Dan Nissenbaum和shakurov所指出的那样.但这也是有效的:

void print(B& input)
{
    input.getValue();
}
Run Code Online (Sandbox Code Playgroud)

这是因为我们明确地说输入是B的对象.编译器知道B的所有对象都保护了对getValue的访问.在我们传递A&的情况下,该对象可能也是一种C类型,可以通过私有访问从A中获取.


sha*_*rov 6

让我们忘记关于模板的一分钟,看看这个:

 class A {
   protected:
     int value;
     int getValue() { return value; }
   public:
     A(int value) { this->value = value; }
 };

 class B : protected A {
   public:
     B() : A(0) { /* Fake value */ }
     void print(A& input) {
       cout << input.getValue() << endl;
     }
 };
Run Code Online (Sandbox Code Playgroud)

print()方法的实现是错误的,因为您无法访问A内部的非公共成员B.这就是为什么:从内部B,你只能访问非公开成员B.这些成员可能是继承的,也可能不是 - 这没关系.

另一方面,A& input可能不是对实例的引用B.它可能是对另一个子类的引用(可能很难getValue()访问).