【问题标题】:Make all derived template classes friend of other class in C++使所有派生模板类成为 C++ 中其他类的朋友
【发布时间】:2018-12-15 01:04:42
【问题描述】:

假设我必须遵循层次结构:

template<class T> class Base {
protected:
    T container;
};

template<class T> class Derived1 : public Base<T> {
public:
    void f1() {
        /* Does stuff with Base<T>::container */
    }
};

template<class T> class Derived2 : public Base<T> {
public:
    void f2() {
        /* Does stuff with Base<T>::container */
    }
};

现在我想要一个独立的类(不是从 Base 派生的),它可以直接从 Base 或任何派生类访问 Base&lt;T&gt;::container。我阅读了模板朋友类,这似乎是我的问题的解决方案,但我还无法弄清楚语法。 我正在寻找类似的东西:

template<class T> class Foo{
    template<T> friend class Base<T>; // <-- this does not work
public:
    size_t bar(const Base<T> &b) const{
        return b.container.size();
    }
};

Derived1<std::vector<int> > d;
d.f1();
Foo<std::vector<int> > foo;
size_t s = foo.bar()

friend 类行 导致error: specialization of ‘template&lt;class T&gt; class Base’ must appear at namespace scope template&lt;T&gt; friend class Base&lt;T&gt; 并且成员变量container 仍然无法访问。

【问题讨论】:

  • 那里不需要template&lt;T&gt;
  • friend 则以另一种方式完成:Base 可以授予访问权限。 Foo 不能假装是Base 的朋友。
  • 显然我的思维方式有两个重大错误。首先,在错误的位置声明朋友类,其次,在朋友类之后放置一个(在我的情况下)不必要的模板参数。非常感谢@aschepler 的全面回答。还要感谢 Dmytro Dadyka,链接讨论的评分最高的答案也很有帮助。

标签: c++ templates inheritance friend-class


【解决方案1】:

几个问题:

就像你在定义类模板时没有在类名后面加上&lt;T&gt;

template <class T> class X<T> { ... }; // WRONG
template <class T> class X { ... };    // RIGHT

在声明类模板时,无论是在前向声明中还是在友元声明中,都不应该将它放在类名之后:

template <class T> class X<T>; // WRONG
template <class T> class X;    // RIGHT - declares the template exists
template <class T> friend class X<T>; // WRONG
template <class T> friend class X;    // RIGHT - says all specializations of X are friends

(除非你正在创建一个类模板部分特化。例如,如果类模板X 已经声明,那么template &lt;class T&gt; class X&lt;T*&gt; { ... }; 定义一个部分特化,当模板参数为一个指针。)

并且你有向后的朋友声明:它需要出现在具有非公共成员的类中,并命名允许使用成员的其他类。 (如果它反过来工作,那么任何新类都可以访问任何其他类的私有和受保护成员,而无需拥有类的许可!)

所以你需要:

template <class T> class Foo;

template<class T> class Base {
    template <class U> friend class Foo;
protected:
    T container;
};

Foo 的前向声明有时不需要,但我认为它使事情变得更清晰,并且当命名空间、嵌套类等变得更加复杂时,它可以避免陷阱。

【讨论】:

    【解决方案2】:

    只有Base 可以说Foo 是它的朋友。

    template<typename T> friend class Foo; // every Foo<T> is a friend of Base
    

    【讨论】:

      猜你喜欢
      • 2012-03-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-29
      • 2019-09-15
      • 2017-02-09
      • 1970-01-01
      • 2019-12-21
      相关资源
      最近更新 更多