【问题标题】:Friend function not allowed to access private member好友功能不允许访问私人会员
【发布时间】:2015-09-10 01:15:34
【问题描述】:

我认为朋友功能可以访问所有成员。即使在这个问题上它也有效:
C++ friend function can't access private members

该问题中给出的答案似乎与我的代码相同,并且他的编译良好,而我的只是说 array_ 是 pivate。有人知道为什么吗?

.h:

#ifndef matrix_h
#define matrix_h

#include <iostream>
using namespace std;

template <typename Comparable>
class matrix
{
    private:
        size_t num_cols_;
        size_t num_rows_;
        Comparable **array_;

    public:
        friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
        size_t NumRows();
        size_t NumCols();
};
#endif

.cpp:

#include <iostream>
#include "matrix.h"

using namespace std;

template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){
    size_t c = rhs.NumRows();
    size_t d = rhs.NumCols();
    for (int i = 0; i < c; i++){
        for (int j = 0; j < d; j++){
            o << rhs.array_[i][j];         //not allowed
        }
        o << endl;
    }
    return o;
}

template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
    return num_rows_;
}

template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
    return num_cols_;
}


int main(){
    matrix<int> a;
    cout << a << endl;

}

【问题讨论】:

  • 您已声明朋友函数采用const matrix&lt;Comparable&gt; &amp;,但它的定义采用matrix&lt;Comparable&gt; &amp;。它们的功能不同。
  • 如果我将它们都设为 const 或删除 const,则会出现未定义的引用错误。对运算符 的未定义引用
  • 危险:Rule of Three 违规。如果复制或移动矩阵,您的矩阵将出现不幸且可能致命的行为。
  • 我有一个构造函数/析构函数/复制重载。我只是没有包括它,因为它无关紧要。我也不应该使用 .cpp 吗?

标签: c++ operator-overloading friend


【解决方案1】:

假设您在这两个地方都使用了const,并将const 添加到numRowsnumCols 的声明中。那么有什么问题呢?嗯……

您认为它是相同的,但您的代码有一个模板。还有朋友声明

friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);

不是模板,所以不符合定义

template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){ // ...

其中一个模板。事实上 gcc 会给出警告:

matrix.h:16:79: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, const matrix<Comparable>&)’ declares a non-template function [-Wnon-template-friend]
         friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
                                                                               ^
matrix.h:16:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here) 

将所有专业都加为好友很诱人,如下所示:

template <typename T>
friend ostream& operator<< (ostream& o, const matrix<T> & rhs);

不幸的是,由于此处解释的原因,这不起作用:Why can templates only be implemented in the header file? 您将能够编译 matrix.cpp,但不能编译单独的驱动程序,如下所示:

#include <iostream>
#include "matrix.h"
using namespace std;
int main() {
    matrix<int> m;
    cout << m << endl;
}

您收到未定义的引用错误。相反,您真的应该在标题中定义整个矩阵类并放弃 .cpp 文件。

需要指出的是,这还是有问题的:你可以叫这个operator&lt;&lt;就好了,但是你不能,比如说,取它的地址,因为它只能通过argument-dependent lookup找到。

auto ptr = static_cast<ostream&(*)(ostream&, const matrix<int>&)>(operator<<); // error

要通过非限定查找找到它,它必须在命名空间范围内具有匹配的声明。而且实际上不可能写出这样的声明(C++的语法没有办法做到)!为了解决这个问题,我们需要将operator&lt;&lt; 变成一个函数模板,内联定义:

template <typename Comparable>
class matrix {
    // ...
    template <typename T>
    friend ostream& operator<<(ostream& o, const matrix<T>& rhs) {
        // ...
    }
    // ...
};
// namespace-scope declaration
template <typename T>
ostream& operator<<(ostream& o, const matrix<T>& rhs);

现在上面的代码获取运营商的地址就可以了。

【讨论】:

    【解决方案2】:
    1. 编译器报错是因为你实现的函数与你声明的函数不同(在声明中 rhs 由 const 修饰,在实现中不是)。
    2. 在实现中添加 const 后,编译器会报错“未定义的引用”,因为声明和实现仍然不一样。实现是模板函数,声明不是。

      #ifndef matrix_h
      #define matrix_h
      
      #include <iostream>
      using namespace std;
      
      template <typename Comparable>
      class matrix
      {
          private:
              size_t num_cols_;
              size_t num_rows_;
              Comparable **array_;
      
          public:
              template<typename T>
              friend ostream& operator<< (ostream& o, const matrix<T> & rhs);
              size_t NumRows() const;
              size_t NumCols() const;
      };
      
      template <typename Comparable>
      ostream& operator<< (ostream& o, const matrix<Comparable> & rhs){
          size_t c = rhs.NumRows();
          size_t d = rhs.NumCols();
          for (int i = 0; i < c; i++){
              for (int j = 0; j < d; j++){
                  o << rhs.array_[i][j];         //not allowed
              }
              o << endl;
          }
          return o;
      }
      
      template <typename Comparable>
      size_t matrix<Comparable>::NumRows() const{
          return num_rows_;
      }
      
      template <typename Comparable>
      size_t matrix<Comparable>::NumCols() const{
          return num_cols_;
      }
      
      #endif
      

    【讨论】:

      猜你喜欢
      • 2021-11-15
      • 2021-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-05
      相关资源
      最近更新 更多