如何隐藏除T类之外的所有人的数据

时间:2012-03-17 21:52:12

标签: c++ templates friend information-hiding access-protection

我想要一个类型 A ,它会将其隐藏的数据提供给 T 类型的对象,但是会隐藏其他所有人的数据。我的C ++编译器碰巧是GCC 4.4,但这并不重要。为什么这不起作用?

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend class T;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return a.n1; }
    B() {}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

顺便说一下,这样可以正常工作,除了它无法隐藏数据:

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    int n() const { return n1; }
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return a.n(); }
    B() {}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

C ++是否真的不允许在编译时将友元类指定为模板参数?为什么不?如果没有,那么我应该使用什么替代技术来隐藏基准? (如果可能,人们更喜欢编译时技术。)

请问我的误会是什么?

(我看到相关问题herehere,的一些答案,但要么他们没有回答我的特定问题,要么我不理解他们这样做了。无论如何,也许我正在使用完全错误的技术。虽然我仍然对朋友类T 失败的原因感兴趣,但我真正想知道的是如何隐藏数据,无论是与朋友还是通过其他方式。)

感谢。

2 个答案:

答案 0 :(得分:4)

你的编译器太旧了。 C ++ 11允许您将模板参数声明为朋友。

§11.3 [class.friend] p3

  

未声明函数的朋友声明应具有以下形式之一:

     
      
  • friend elaborated-type-specifier ;
  •   
  • friend simple-type-specifier ;
  •   
  • friend typename-specifier ;
  •   
     

如果friend声明中的类型说明符指定(可能是cv限定的)类类型,则该类声明为friend;否则,朋友声明被忽略。

它甚至包含一个模板参数作为朋友的例子:

class C;
// [...]
template <typename T> class R {
  friend T;
};

R<C> rc;   // class C is a friend of R<C>
R<int> ri; // OK: "friend int;" is ignored

C ++ 03遗憾地无法做到这一点,但是你可以简单地将一个自由函数联系起来,让它作为“粘合”代码,从一个类中获取数据并将其传递给另一个类。另一种方式可能是passkey pattern

答案 1 :(得分:1)

我不知道你的错误背后的标准(参考Xeo的答案),但我确实找到了C ++ 03的解决方法。 不要让T成为朋友,而是让T的一个成员函数成为朋友:

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend int T::getN1(const A& a) const;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return getN1(a); }
    B() {}
  private:
    int getN1(const A<B>& a) const {return a.n1;}
};

class C {
  public:
    int f(const A<B> a) const { return getN1(a); }
    C() {}
  private:
    // Error, n1 is a private member of A<B>
    int getN1(const A<B>& a) const {return a.n1;}
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}

或者,您可以使T的嵌套类/结构成为A的朋友。如果您希望T有多个A的私有成员可以访问,这可能会更方便。

#include <iostream>

template <class T> class A {
  private:
    int n1;
  public:
    friend class T::AccessToA;
    A(const int n0 = 0) : n1(n0) {}
};

class B {
  public:
    int f(const A<B> a) const { return AccessToA::getN1(a); }
    B() {};
  private:
    friend class A<B>;
    struct AccessToA
    {
        static int getN1(const A<B>& a) {return a.n1;}
    };
};

class C {
  public:
    int f(const A<B> a) const { return AccessToA::getN1(a); }
    C() {};

  private:
    friend class A<C>;
    struct AccessToA
    {
        // Error, n1 is a private member of A<B>
        static int getN1(const A<B>& a) {return a.n1;}
    };
};

int main() {
    const A<B> a(5);
    const B b;
    const int m = b.f(a);
    std::cout << m << "\n";
    return 0;
}