将派生类的构造函数声明为父类的友元

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 参数足以消除歧义。

以上是关于将派生类的构造函数声明为父类的友元的主要内容,如果未能解决你的问题,请参考以下文章

虚函数本质

类与类之间的友元关系可以继承吗? 友元函数是类的成员函数吗?

4月14日继承与多态

派生类可以使用基类的友元函数吗?

用于极坐标到矩形转换的坐标类的友元函数

sdut 3-7 类的友元函数的应用