如何隐藏一个数据,让除了T班级以外的人都看不到

5
我希望有一种类型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++真的不允许将友元类作为模板参数在编译时指定吗?为什么不行?如果不行,那么我应该使用什么替代技术来隐藏数据?(如果可能的话,最好使用编译时技术。)
这里我的误解是什么,请问?
(我看到了一些相关问题的答案这里这里,但它们要么没有回答我的问题,要么我无法理解它们是否回答了我的问题。无论如何,也许我完全使用了错误的技术。虽然我仍然对为什么friend class T失败感兴趣,但我真正想知道的是如何隐藏数据,无论是通过友元还是其他方式。)
谢谢。
2个回答

4

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

§11.3 [class.friend] p3

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

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

如果在友元声明中的类型指示符指定了一个(可能带有cv修饰符的)类类型,则该类被声明为友元;否则,该友元声明将被忽略。

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

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遗憾地没有办法做到这一点,但是您可以简单地将单个自由函数作为“粘合”代码添加为好友,并让它将一个类的数据传递给另一个类。另一种方法可能是传递密钥模式


我明白了。谢谢你。也感谢你提供的启示性通行证链接。 - thb

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的友元。如果有几个A的私有成员需要T访问,则这可能更方便。

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

好的建议。除非我能想出更好的方法,否则我应该遵循这个建议。谢谢。 - thb
还要查看Xeo提出的passkey习语和Attorney-Client习语。我已经很久没有阅读过这些内容了,因此我的解决方案可能是这些习语的变体。 - Emile Cormier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接