在自定义类中重载ostream运算符

时间:2016-09-15 13:31:51

标签: c++ operator-overloading ostream

我正在尝试使用自定义矩阵类的CRTP。现在我正在尝试重载ostream运算符,请按https://msdn.microsoft.com/en-us/library/1z2f6c2k.aspx

然而,一切似乎都在编译,但程序从不存在,并且在屏幕上不打印任何内容。正如所发生的那样,我正在摸不着头脑。

无论如何,这是相关代码(抱歉它有点冗长)

#ifndef EXPERIMENT_POINTERMATRIX_H
#define EXPERIMENT_POINTERMATRIX_H

#include <cstdlib>
#include <ostream>
#include "macro.h"
namespace PM {
    template<typename T, typename Derived>
    class MatrixBase{
    public:
        size_t nRow;
        size_t nCol;

        MatrixBase(const size_t nRow_,const size_t nCol_):nRow(nRow_), nCol(nCol_){}
        Derived& derived(){
            return *static_cast<Derived*>(this);
        }
        const Derived& derived() const{
            return *static_cast<Derived*>(this);
        }

        T& operator()(const size_t i, const size_t j){
            CHECK_BOUND(i,j,*this);
            return derived().operator()(i,j);
        }
        const T& operator()(const size_t i, const size_t j) const {
            return const_cast<T&>(
                    static_cast<const MatrixBase<T, Derived>&>(*this).operator()(i,j));

        }

        inline T rows(){
            return nRow;
        }
        const T rows() const {
            return nRow;
        }
        inline T cols(){
            return nCol;
        }
        const T cols() const {
            return nCol;
        }
        template<typename t1, typename t2>
        friend std::ostream& operator<<(std::ostream& os, const MatrixBase<t1, t2> & matrix);
    };
    template<typename t1, typename t2>
    std::ostream& operator<<(std::ostream& os, const MatrixBase<t1, t2>& matrix){

        for (size_t i =0;i<matrix.rows();i++){

            os << matrix(i,0);
            if (matrix.cols()>1) {
                for (size_t j = 1; j < matrix.cols(); j++) {
                    os << "," << matrix(i, j);
                }
            }
            os << std::endl;
        }
        return os;
    };

    template<typename T, typename Derived>
    class Matrix : public MatrixBase<T, Matrix<T, Derived>>{
    public:
        T * data;

        Matrix(const size_t nRow, const size_t nCol):MatrixBase<T, Matrix<T, Derived>>(nRow, nCol){
            data = (T*) malloc(sizeof(T)*nRow*nCol);
        }

        ~Matrix(){
            free(data);
        }
        Derived& derived(){
            return *static_cast<Derived*>(this);
        }
        const Derived& derived() const{
            return *static_cast<Derived*>(this);
        }

        T& operator()(const size_t i, const size_t j){
            return derived().operator()(i,j);
        }


    };

    template<typename T, typename Derived>
    class MatrixView : public MatrixBase<T, MatrixView<T, Derived>>{
    public:
        T * data;
        MatrixView(const size_t nRow, size_t nCol, T * other):MatrixBase<T, MatrixView<T, Derived>>(nRow, nCol), data(other){}
        T& operator()(const size_t i, const size_t j){
            return derived().operator()(i,j);
        }
        Derived& derived(){
            return *static_cast<Derived*>(this);
        }
        const Derived& derived() const{
            return *static_cast<Derived*>(this);
        }
    };

    template<typename T>
    class MatrixRowMajor: public Matrix<T, MatrixRowMajor<T>>{
    public:

        MatrixRowMajor(const size_t nRow, const size_t nCol):Matrix<T, MatrixRowMajor<T>>(nRow, nCol){}
        T& operator()(const size_t i, const size_t j){
            using base = MatrixBase<T, Matrix<T, MatrixRowMajor<T>>>;
            using super = Matrix<T, MatrixRowMajor<T>>;
            return super::data[i*base::nCol+j];
        }
    };
    template<typename T>
    class MatrixColMajor: public Matrix<T, MatrixColMajor<T>>{
    public:
        MatrixColMajor(const size_t nRow, const size_t nCol):Matrix<T, MatrixColMajor<T>>(nRow, nCol){}
        T& operator()(const size_t i, const size_t j){
            using base = MatrixBase<T, Matrix<T, MatrixColMajor<T>>>;
            using super = Matrix<T, MatrixColMajor<T>>;
            return super::data[i+j*base::nRow];
        }
    };
    template<typename T>
    class MatrixViewRowMajor : public MatrixView<T, MatrixViewRowMajor<T>>{
    public:
        MatrixViewRowMajor(const size_t nRow, const size_t nCol, T* other):MatrixView<T, MatrixViewRowMajor<T>>(nRow, nCol, other){}
        T& operator()(const size_t i, const size_t j){
            using base = MatrixBase<T, Matrix<T, MatrixViewRowMajor<T>>>;
            using super = MatrixView<T, MatrixViewRowMajor<T>>;
            return super::data[i*base::nCol+j];
        }
    };

    template<typename T>
    class MatrixViewColMajor : public MatrixView<T, MatrixViewColMajor<T>>{
    public:
        MatrixViewColMajor(const size_t nRow, const size_t nCol, T* other):MatrixView<T, MatrixViewRowMajor<T>>(nRow, nCol, other){}
        T& operator()(const size_t i, const size_t j){
            using base = MatrixBase<T, Matrix<T, MatrixViewRowMajor<T>>>;
            using super = MatrixView<T, MatrixViewRowMajor<T>>;
            return super::data[i+j*base::nRow];
        }
};
}

void test_print(){
    using namespace PM;
    using namespace std;
    MatrixRowMajor<double> matrix(10, 1);
    for (int i =0;i<matrix.rows();i++){
        matrix(i,0)=1.0;
        std::cout << "i'th entry is " <<matrix(i,0) << std::endl; //This is fine
    }
    std::cout << matrix; //This is not fine
}
#endif //EXPERIMENT_POINTERMATRIX_H

使用g ++ 4.9(启用c ++ 11)编译整个程序

编辑: 为了测试它是否是运算符的问题,我创建了以下方法(在MatrixBase中):

void print(){
            for (size_t i =0;i<this->rows();i++){
                std::cout  << this->operator()(i,0);
                if (this->cols()>1) {
                    for (size_t j = 1; j < this->cols(); j++) {
                        std::cout << "," << this->operator()(i, j);
                    }
                }
                std::cout << std::endl;
            }
        }

并调用matrix.print()之类的方法。这按预期工作。

不幸的是,调试器没有提供有用的信息,因为程序停止在行os&lt;&lt;矩阵(i,0),当我停止程序检索信息时,它表示无法获取帧(Clion作为调试器)

1 个答案:

答案 0 :(得分:1)

MatrixBaseoperator()的成员函数无条件地调用自身,因此无限递归。

const T& operator()(const size_t i, const size_t j) const {
        return const_cast<T&>(
                static_cast<const MatrixBase<T, Derived>&>(*this).operator()(i,j));

    }

此函数是尾递归的,因此可能会导致无限循环,而不是由于调用深度很大而导致崩溃。

与您的问题无关,通常认为在C ++中使用malloc()是不可取的 - 特别是在处理可能与C - 结果不直接兼容的类型(例如C ++类)时,对于您的类的用户,取决于类型T,可以是未定义的。请改用运算符new。更好的是,使用标准容器。