将派生类的构造函数声明为父类的友元
Posted
技术标签:
【中文标题】将派生类的构造函数声明为父类的友元【英文标题】:Declare constructor of a derived class as friend of parent class 【发布时间】:2020-05-17 18:08:04 【问题描述】:作为每个 C++ 新手,我正在编写自己的矩阵类作为练习。我正在使用这样的类模板:
template<typename T>
class BMatrix
public:
// Constructors
BMatrix(unsigned nrows, unsigned ncols);
BMatrix(unsigned nrows, unsigned ncols, T ival);
BMatrix(const BMatrix<T>& a);
// Destructor
~BMatrix();
// Access
T& operator() (unsigned row, unsigned col);
T operator() (unsigned row, unsigned col) const;
// ...
// Friends
//friend BDiagonal<T>::BDiagonal(unsigned size, T val);
private:
unsigned nrows_, ncols_;
T* data_;
;
BMatrix 的构造函数分配一个大小为 nrows_*ncols_ 的数组 data_。
现在,如您所见,我想将另一个类 BDiagonal 的构造函数声明为友元。 BDiagonal 类是 BMatrix 的派生类。这背后的动机是 BDiagonal 将节省内存(我只需要存储 nxn 对角矩阵的 n 个非零元素)并使某些操作更快。所以我希望这个矩阵的构造函数分配一个大小为 nrows*1 的数组 data_,但仍然有 nrows_ 和 ncols_ 大于 1。这样我仍然可以使用我为 BMatrix 类实现的一些功能(例如重载
不出所料,这并没有编译,而是编译器抛出错误:
BArray/core.h:86:9: error: ‘BDiagonal’ does not name a type
friend BDiagonal<T>::BDiagonal(unsigned size, T val);
如果我在我得到的文件开头转发声明 BDiagonal:
BArray/core.h:546:7: error: invalid use of incomplete type ‘class BMatrix<double>’
class BDiagonal : public BMatrix<T>
^~~~~~~~~
BArray/core.h:55:7: note: declaration of ‘class BMatrix<double>’
class BMatrix
我也尝试过声明 BMatrix,但这会导致更多错误。我不想声明 BMatrix 的私有成员受保护,因为这会导致任何人都可以通过派生类直接访问它们。
有没有办法做到这一点?更重要的是,我有什么理由不应该这样做并对我的 BDIagonal 类采取不同的方法?
干杯
【问题讨论】:
请出示BDiagonal
的相关部分。
它为我编译 onlinegdb.com/HyDb--JiU
如果你用现代 c++ 编写,规则是 5,而不是 3,你错过了移动构造函数和移动赋值运算符
除非分配是关于显式动态内存处理,否则请改用std::vector
并遵循零的规则。
【参考方案1】:
如果您需要在派生类中可以访问某些内容,则将其设为受保护而不是私有。在这种情况下你不需要朋友。
您还可以在BMatrix
中添加一个受保护的构造函数,该构造函数使用您可以在派生类构造函数中调用(委托)的所需元素数量来初始化data_
。
例如,您可以在下面添加受保护的构造函数
BMatrix(std::pair<unsigned, unsigned> dimension, unsigned int numElements);
然后在 BMatrix 中你会写
BMatrix(unsigned nrows, unsigned ncols) : BMatrix(nrows, ncols, nrows * ncols)
BDiagonal
的可能构造函数是
BDiagonal(size) : BMatrix(size, size, size)
有了这个BDiagonal
只会为size
元素而不是size*size
分配空间。
编辑
我已将受保护的构造函数更改为接收维度的 std::pair
而不是两个数字,以避免与接收 T ival
的构造函数产生歧义,但还有其他方法可以避免歧义。
【讨论】:
感谢您的优雅回答。现在我有一个不同的问题。我有 2 个 BMatrix 构造函数。一个接受两个参数(nrows,ncols),我将它委托给 3 args protected 构造函数,如您的示例所示。然后我有一个 3 args 构造函数(比如 2 个 args 加上一个用于填充矩阵的初始值),我将它委托给另一个接受 4 个 args 的受保护构造函数。当我从 main() 声明 BMatrix a(1,2,3) 时,编译器说调用不明确,因为有 2 个候选者需要 3 个参数。但是其中一个是受保护的,所以我不希望我可以从 main 调用它。 例如,如果我从 main 尝试 BMatrix a(1,2,3,4),编译器会说它是受保护的。 (现在我认为声明BMatrix的私有成员protected可能是最简单的解决方案,我只是想加深对问题的理解)。 哦,我明白了,我建议的受保护构造函数可能与接收初始值的构造函数发生冲突。有多种方法可以解决这个问题。我已经用一种可能的方式更新了答案。 那就更好了。每个矩阵都有一个由派生类构造函数设置的“名称”,受保护构造函数中的extra std::string
参数足以消除歧义。以上是关于将派生类的构造函数声明为父类的友元的主要内容,如果未能解决你的问题,请参考以下文章