Home > Mobile >  Trouble with a copy-constructor in C using templates
Trouble with a copy-constructor in C using templates

Time:02-27

It has been more than a decade since the last time I wrote something in C/C and now I have a problem I cannot solve. Basically I have two classes, say CA and CB, where CA looks like a vector and CB looks like a two-dimensional matrix.

The issue that I am facing is that I want to construct an object of type CB and do so by using another object of type CB. Therefore, I pass as a parameter an object of type CB that has been initialized correctly, but when I do that, I get an error of the form ./B.h:97:43: error: no viable overloaded operator[] for type 'const CB<double>'.

The way I copy the object is by relying on the copying mechanism for class CA. Having said that, constructing an object of class CA by using another initialized object of class CA appears to be working fine. So, I am a little bit lost as to what is wrong. I also get additional help from the compiler for my error, but I am not sure how to fix things really. The full error that I receive using g is the following:

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.

There must be something that I do not remember how to do, or most likely, I am not aware of. Note that if you comment the offending line fromm main.cpp (line 24) with the command CB<double> myPrecious(mycb_c);, then the program compiles without a problem and the output is fine.

I tried to create a minimal example and this is as far as I could shrink the code.

Any ideas on how to make the constructor work by using copy? I appreciate your time.

BELOW ARE THE FILES

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

CodePudding user response:

The problem is that currently you have overloaded operator[] as a non-const member function of class template CB. This means that the implicit this parameter of this member function is of type CB<DataType>*. Meaning that we can use this member function only with non-const objects.

To solve this problem you need to make it(overload it as) a const member function instead by adding a const as shown below, so that now the implicit this parameter will be of type const CB<DataType>* meaning now it can be used with const objects.

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

The program compiles after the modification as can be seen here.

  • Related