5

Я хочу типа что даст его скрытую точку привязки к объекту типа 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++ действительно не позволяют друг класса должны быть указаны во время компиляции в качестве параметра шаблона? Почему нет? Если нет, то какую альтернативную технику я должен использовать, чтобы скрыть привязку? (Можно было бы, по возможности, предпочесть технику компиляции).

Каково мое недоразумение здесь, пожалуйста?

(Я вижу некоторые ответы на связанные вопросы here и here,, но либо они не отвечают на мой конкретный вопрос, либо я не понимаю, что они это делают. Во всяком случае, возможно, я использую неправильную технику вообще. остаются заинтересованы в том, почему класс друга T не удается, что я действительно хочу знать, так это, как скрыть данные, как с другом, так и с помощью других средств.)

Спасибо.

ответ

1

Я не знаю стандартного за вашей ошибкой (см. Ответ Xeo), но я нашел обходное решение для C++ 03. Вместо того, чтобы T друг, сделать одну из функций членов T «s друга:

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

В качестве альтернативы, вы можете сделать вложенный класс/Т-структуру из быть другим А. Это может быть более удобно, если есть несколько частных членов 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; 
} 
+0

Хороший совет. Если я не смогу придумать что-то лучше, я должен следовать совету. Спасибо. – thb

+0

Также ознакомьтесь с идиомой passkey, предложенной Xeo, а также идиомой Адвокат-Клиент. Прошло некоторое время с тех пор, как я прочитал об этом, поэтому мое решение вполне может быть вариантом этих идиом. –

4

Ваш компилятор просто слишком стар. C++ 11 позволяет объявлять параметры шаблона в качестве друзей.

§11.3 [class.friend] p3

друг заявление, не объявить функцию должны иметь одну из следующих форм:

  • friendelaborated-type-specifier;
  • friendsimple-type-specifier;
  • friendtypename-specifier;

Если тип спецификатор в friend декларации обозначает (возможно, резюме квалифицированных) тип класса, что класс объявлен как 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.

+0

Вижу. Спасибо. Благодарим вас за освещенную ссылку на ссылку. – thb