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

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

提问人:MightyMouse 提问时间:2/27/2022 更新时间:2/27/2022 访问量:166

问:

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

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

我复制对象的方法是依靠类 CA 的复制机制。话虽如此,通过使用类 CA 的另一个初始化对象来构造类 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.

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

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

关于如何使用 copy 使构造函数工作的任何想法?感谢您抽出宝贵时间。

以下是文件

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

啊:

#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(); 
}
C++ 模板 复制构造函数

评论

2赞 fabian 2/27/2022
您需要重载该运算符才能也可用于 const 对象:virtual CA<DataType> const& operator[] (int index) const;
0赞 MightyMouse 2/27/2022
谢谢。我还解决了我遇到的另一个错误(在第 105 行而不是调用我应该有.无论如何,谢谢你。这花费了我比应有的时间更多的时间,正如我最初想到的那样,这是一个简单的错误。如果你愿意,你可以把这句话作为答案,我会接受的。deleteRows()theRows = NULL;

答:

1赞 user12002570 2/27/2022 #1

问题是目前您已经重载为类模板的非常量成员函数。这意味着此成员函数的隐式 this 参数的类型为 。这意味着我们只能将这个成员函数用于非常量对象。operator[]CBCB<DataType>*

为了解决这个问题,你需要通过添加一个(重载它作为)一个const成员函数,如下所示,这样现在隐式这个参数将是类型,这意味着现在它可以与对象一起使用。constconst 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

该程序在修改后编译,如下所示