0

Please help me correcting following error.

Error 1 error C2248: 'SquareMatrix::SquareMatrix' : cannot access private member declared in class 'SquareMatrix'

I am trying to implement a subclass(square matrix) under class(matrix) and I don't know how to fix the error. Here is the code.

#ifndef _MATRIX_
#define _MATRIX_

#include <iostream>
#include <vector>
using namespace std;

//class matrix starts here

template<class T, int m, int n>
class Matrix{

    vector<vector<T>> elements;
    int nrow;
    int ncol;

public:
    Matrix();
    ~Matrix();

template<class T, int m, int n>
Matrix<T, m, n>::Matrix() : nrow(m), ncol(n){
    for (int i = 0; i < nrow; i++){
        vector<T> row(ncol, 0);
        elements.push_back(row);
    }
}

template<class T, int m, int n>
Matrix<T, m, n>::~Matrix(){}

//here is the inheritance class SquareMatrix

template<class T, int n>
class SquareMatrix : public Matrix<T, n, n>{

    SquareMatrix();
};

template<class T, int n>
SquareMatrix<T, n>::SquareMatrix() :nrow(n), ncol(n){
    for (int i = 0; i < nrow; i++){
        vector<T> row(ncol, 0);
        elements.push_back(row);
    }
}

//Here is the main.cpp

#include "Matrix.h"
using namespace std;

int main(){
    Matrix<double, 3, 2> a;
    SquareMatrix<double, 3> c;
}
ArK
  • 20,698
  • 67
  • 109
  • 136
SungwonAhn
  • 57
  • 8
  • While fixing this, there is a surprising (to you) amount of code that can simply be thrown away. – WhozCraig Apr 06 '16 at 03:11
  • I am a beginner learning c++. I had hard time understanding the template, you gave me much simpler one. Thank you for the comment and example!! – SungwonAhn Apr 06 '16 at 05:09

2 Answers2

2

The problem you're experiencing surfaces by trying to initialize the member variables of your base class in your derived class constructor's member initializer list. Unless the base is a virtual-base, that isn't required, nor even allowed. Instead, simply kick the can down the road to the base class and have its constructor initialize those members:

template<class T, int n>
SquareMatrix<T, n>::SquareMatrix() : Matrix<T,n,n>()
{
}

In case you didn't notice, this also fixes another logic defect in your posted code. Populating the actual elements vector is already done by your base class, thus you don't need that in your derived class as well. Invoking base-class constructing handles it for you.

Improvements

Below is a list of things that can be done to considerably simplify this code:

  • The matrix dimension template parameters should be an unsigned data type. You can't have negative dimensions of a matrix, so code to not even allow it.
  • The row elements of your matrix are needlessly also dynamic (vectors) rather than fixed (arrays). Having the entire structure supported by dynamic memory makes sense, but since template parameters are used for declaring dimensions, you can use std::array<T,n> for the row-type, and wrap that in a dynamic std::vector of size m
  • The ncol and nrow members should never change for the life of a matrix, as they in-fact template parameter based. Change them to public static constexpr if you want to keep them (though honestly I see no reason you want to; m and n come along everywhere your template does.
  • The base class, being little more than a constriction to use the same width and height, doesn't even need a separate class derivation; you can simply do it with a using alias.

In the end, the code reduces to this:

#include <vector>
#include <array>

// matrix managed on the heap as a vector of arrays
template<class T, size_t m, size_t n>
class Matrix
{
    std::vector<std::array<T, n>> elements;

public:
    static constexpr size_t nrows = m;
    static constexpr size_t ncols = n;

    Matrix() : elements(m)
    {
    }
};

The derived square matrix class is so-far-reduced it can be a simple using alias:

// a square matrix built via a regular matrix
template<class T, size_t m>
using SquareMatrix = Matrix<T,m,m>;

And of course, access to the elements member in some fashion still needs to be provided, otherwise most of this is rather pointless.

Best of luck, and I hope it helps.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
1
SquareMatrix<T, n>::SquareMatrix() :nrow(n), ncol(n){

Your constructor here is attempting to initialize its members nrow, and ncol.

The problem with that, of course, is that this class does not have any members called nrow and ncol. They are private members of its superclass.

A template is a class. A class's constructor can only initialize its own members. It cannot initialize any members of its superclass. The superclass's constructor is responsible for initializing its own members.

You didn't specify which compiler you're using, but that's a really terrible error message. gcc's error message makes much more sense:

t.C:40:37: error: class ‘SquareMatrix<T, n>’ does not have any field named ‘nrow’
 SquareMatrix<T, n>::SquareMatrix() :nrow(n), ncol(n){

P.S. Do yourself a favor, and completely forget about "using namespace std;". Just pretend there's no such thing in C++. Especially in header files.

Community
  • 1
  • 1
Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148