使用模板的 C++ 中的复制构造函数出现问题

Trouble with a copy-constructor in C++ using templates

距离我上次在C/C++写东西已经十多年了,现在我有一个我无法解决的问题。基本上我有两个 classes,比如说 CA 和 CB,其中 CA 看起来像一个向量 CB 看起来像一个二维矩阵.

我面临的问题是我想构造一个 CB 类型的对象,并通过使用另一个 CB 类型的对象来实现。因此,我将一个已正确初始化的 CB 类型的对象作为参数传递,但是当我这样做时,我收到 ./B.h:97:43: error: no viable overloaded operator[] for type 'const CB<double>'.

形式的错误

我复制对象的方式是依靠class CA的复制机制。话虽如此,通过使用 class CA 的另一个初始化对象构建 class CA 的对象似乎工作正常。所以,我对出了什么问题有点迷茫。对于我的错误,我还从编译器获得了额外的帮助,但我不确定如何真正解决问题。我使用 g++ 收到的完整错误如下:

In file included from main.cpp:1:
./B.h:97:43: error: no viable overloaded operator[] for type 'const CB<double>'
        (*theRows)[i] = new CA <DataType>(m[i]);
                                          ^ ~
./B.h:105:2: note: in instantiation of member function 'CB<double>::copy' requested here
        copy(a);
        ^
main.cpp:24:16: note: in instantiation of member function 'CB<double>::CB' requested here
    CB<double> myPrecious(mycb_c);
               ^
./B.h:21:27: note: candidate function not viable: 'this' argument has type 'const CB<double>', but method is not marked const
    virtual CA<DataType>& operator[] (int index);
                          ^
1 error generated.

一定是有些事情我不记得怎么做了,或者很可能我不知道。请注意,如果您使用命令 CB<double> myPrecious(mycb_c); 注释违规行 fromm main.cpp(第 24 行),则程序编译没有问题并且输出正常。

我尝试创建一个最小的示例,这是我可以缩小代码的范围。

关于如何使用复制使构造函数工作有什么想法吗?感谢您的宝贵时间。

以下是文件

main.cpp:

#include "B.h"

int main()
{
    CA<double> myca_a(3);
    CA<double> myca_b(myca_a);
    
    CB<double> mycb_c(2, 3, 3.0);
    CB<double> mycb_d(3, 2, 4.0);
    CB<double> mycb_e;
    
    cout << "<separator>" << endl;
    cout << myca_a << endl;
    cout << "<separator>" << endl;
    cout << myca_b << endl;
    cout << "<separator>" << endl;
    cout << mycb_c << endl;
    cout << "<separator>" << endl;
    cout << mycb_d << endl;
    cout << "<separator>" << endl;
    cout << mycb_e << endl;
    cout << "<separator>" << endl;
    
    CB<double> myPrecious(mycb_c);

    return 0;
}

A.h:

#include <iostream>
using namespace std;

template <class DataType>
class CA
{
protected:
    DataType* paDataType;
    int _size;
    void copy(const CA<DataType>& ac);

public:
    CA();
    CA(int n);
    CA(int n, const DataType& o);
    CA(const CA<DataType>& ac);
    virtual ~CA();

    int size() const;
    DataType& operator [] (int k);
    void operator= (const CA<DataType>& ac);
    friend ostream& operator<<(ostream& os, CA<DataType>& a) {
        os << "[";
        for (int i = 0; i < a.size() - 1; i++)
            os << a[i] << " ";
        os << a[a.size() - 1] << "]";
        return os;
    }
};


//Empty constructor
template <class DataType>
CA<DataType>::CA()
{
    paDataType = new DataType[1];
    _size = 1;
}

//Constructor
template <class DataType>
CA<DataType>::CA(int n)
{
    paDataType = new DataType[n];
    _size = n;
}

//Constructor w/ value
template <class DataType>
CA<DataType>::CA(int n, const DataType& o)
{
    paDataType = new DataType[n];
    _size = n;
    for (int i = 0; i < _size; i++) paDataType[i] = o;
}

//Copy Constructor
template <class DataType>
CA<DataType>::CA(const CA<DataType>& ac)
{
    copy(ac);
}

//Copy method
template <class DataType>
void CA<DataType>::copy(const CA<DataType>& ac)
{
    paDataType = new DataType[ac._size];
    _size = ac._size;
    
    for (int i = 0; i < _size; i++)
        paDataType[i] = ac.paDataType[i];
}

//Destructor
template<class DataType>
CA<DataType>::~CA()
{
    if (paDataType != NULL)
        delete[] paDataType;
    paDataType = NULL;
    _size = 0;
}

//Size method
template <class DataType>
int CA<DataType>::size() const
{
    return _size;
}

//Accessor
template <class DataType>
DataType& CA<DataType>::operator [] (int k)
{
    return paDataType[k];
}

//Overloaded assignment operator
template <class DataType>
void CA<DataType>::operator= (const CA<DataType>& ac)
{
    if (paDataType != NULL) delete[] paDataType;
    copy(ac);
}

B.h:

#include "A.h"

template <class DataType>
class CB : public CA <CA <DataType> >
{
protected:
    CA < CA<DataType>* >* theRows;
    void copy(const CB<DataType>& m);
    void deleteRows();

public:
    CB();
    CB(int n, int m);
    CB(int n, int m, DataType v);
    CB(const CB& a);
    virtual ~CB();
    void operator= (const CB<DataType>& a);
    virtual int size() const;
    int columns();
    int rows();
    virtual CA<DataType>& operator[] (int index);
    friend ostream& operator<<(ostream& os, CB<DataType>& m) {
        
        int rows = m.rows();
        int cols = m.columns();
        os << "----------" << endl;
        for (int i = 0; i < rows-1; i++) {
            for (int j = 0; j < cols-1; j++) {
                os << m[i][j] << " ";
            }
            os << m[i][cols-1] << endl;
        }
        for (int j = 0; j < cols-1; j++) {
            os << m[rows-1][j] << " ";
        }
        os << m[rows-1][cols-1] << endl;
        os << "----------";

        return os;
    }
};

template <class DataType> CB<DataType>::CB() {
    theRows = new CA <CA <DataType>* >(1, NULL);
    (*theRows)[0] = new CA <DataType>();
}

template <class DataType>
CB<DataType>::CB(int n, int m)
{
    theRows = new CA <CA <DataType>* >(n, NULL);
    for (int i = 0; i < n; i++)
    {
        (*theRows)[i] = NULL;
        (*theRows)[i] = new CA <DataType>(m);
    }
}

template <class DataType>
CB<DataType>::CB(int n, int m, DataType v)
{
    theRows = new CA <CA <DataType>* >(n, NULL);
    for (int i = 0; i < n; i++)
    {
        (*theRows)[i] = new CA <DataType>(m, v);
    }
}

template <class DataType>
void CB<DataType>::deleteRows()
{
    if (theRows != NULL) 
    { 
        for (int i = 0; i < theRows->size(); i++) 
        { 
            if ((*theRows)[i] != NULL) delete (*theRows)[i];        
            (*theRows)[i] = NULL; 
        }
        delete theRows; 
    }   
    theRows = NULL;
}

template <class DataType>
CB<DataType>::~CB()
{
    deleteRows();
}

template <class DataType>
void CB<DataType>::copy(const CB<DataType>& m)
{
    deleteRows();
    theRows = new CA <CA <DataType>* >(m.size(), NULL);
    for (int i = 0; i < m.size(); i++)
    {
        (*theRows)[i] = new CA <DataType>(m[i]);
    }
}

template <class DataType>
CB<DataType>::CB(const CB<DataType>& a)
{
    deleteRows();
    copy(a);
}

template <class DataType>
void CB<DataType>::operator= (const CB<DataType>& a)
{
    copy(a);
}

template <class DataType>
int CB<DataType>::size() const
{
    return theRows->size();
}

template <class DataType>
CA<DataType>& CB<DataType>::operator[] (int index)
{
    return (*(*theRows)[index]);
}

template <class DataType>
int CB<DataType>::rows()
{ 
    return theRows->size(); 
}

template <class DataType>
int CB<DataType>::columns()
{ 
    return (*this)[0].size(); 
}

问题是目前你已经重载了operator[]作为non-const成员函数 class 模板 CB。这意味着这个成员函数的隐式this参数是CB<DataType>*类型。这意味着我们只能将此成员函数用于 non-const 个对象。

解决这个问题,你需要通过添加[=15]使其成为一个常量成员函数 =] 如下所示,因此现在 隐式 this 参数将是 const CB<DataType>* 类型,这意味着现在它可以与 const 对象一起使用。

template <class DataType>
class CB : public CA <CA <DataType> >
{

    virtual CA<DataType>& operator[] (int index) const; //added const here
    //other members here
}
template <class DataType>
CA<DataType>& CB<DataType>::operator[] (int index) const //added const here
{
    return (*(*theRows)[index]);
}
//other code here

修改后程序编译可见here.