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

标签 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 << matrix(i,0) 行停止,当我停止程序以检索信息时,它说无法获取帧(Clion 作为调试器)

最佳答案

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

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。更好的是,使用标准容器。

关于c++ - 在自定义类中重载 ostream 运算符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39512409/

相关文章:

c++ - 为哈希表获取和设置正确重载 [bracket] 运算符

c++ - 了解 cout.operator<<() 的行为

c++ - "Where"这个重载运算符是否接受 "out"?

c++ - 如何让派生类的流式运算符也输出基类

c++ - 如何强制执行有关指针数据成员的常量正确性

c++ - 链接错误 2019,但原型(prototype)在头文件中

C++ 将 ostream 作为参数传递

c++ - CreateFile 失败并出现错误 ERROR_SHARING_VIOLATION

c++ - 为什么 C++ 编译器找不到运算符 <<

c++ - 这个 typedef 语法是如何工作的..?