首页 文章

(c)重写operator <<打印错误的对象

提问于
浏览
-2

我现在正在为标量和向量进行运算符覆盖,并与运算符<<进行斗争

这是我的代码

主:(我不能改变主...它会像这样给出我只编码cpVector,cpScalar)

#include <iostream>
#include "cpScalar.hpp"
#include "cpVector.hpp"
#include <iostream>
#include <string>

using namespace std;

int main(){

cpScalar arr[4];
for(int i = 0; i < 4; i++){
    arr[i] = cpScalar(i+1);
}
cpVector v1(arr, 4);          // {1, 2, 3, 4}
cpScalar arr2[4];
for(int i = 0; i < 4; i++){
    arr2[i] = cpScalar(i+3);
}
cpVector v2(arr2, 4);         // {3, 4, 5, 6}

cpVector result4 = v2 / v1;   //  {0.3, 0.4, 0.5, 0.6}

cout << result4.getVal(0) << " " ... " "  << result4.getVal(3) << endl;
cout << result4 << endl;
// prints   0.3, 0.4, 0.5, 0.6   and     [, , , ]
}

当我检查结果4的每个值时,我可以找到操作员/工作 . 但是,当我尝试打印整个矢量时,它会打印一个空值 . 这是cpVector类 .

cpVector:

#ifndef CPVECTOR_H
#define CPVECTOR_H
#include "cpScalar.hpp"
#include <iostream>
#include <string>
#include <cassert>

using namespace std;
class cpVector
{
    private:
        cpScalar *data;
        unsigned int size;

    public:
        cpVector() {
            cpScalar s[0];
            data = s;
            size = 0;
        }

        cpVector(cpScalar sarr[], unsigned int s){
            this->size = s;
            data = sarr;
        }

        cpVector operator/(cpVector s){
            assert(size == s.getSize());

            unsigned int x = s.getSize();
            cpScalar denom = s.getAbs();
            cpScalar ans[x];
            for (int i=0; i < x;i++){
                ans[i] = data[i] / denom;
                std::cout << i << "th element: " << ans[i] << std::endl;
            }
            return cpVector(ans, x);
        }

        friend std::ostream& operator<<(std::ostream& s, const cpVector &r);

        cpScalar getVal(int i)const{return data[i];}

        int getSize() const{return size;}

        cpScalar getAbs() const{
            cpScalar sum(0);
            for(int i = 0; i < size; i++){
                cpScalar x = data[i];
                if(x.getDouble() < 0 && x.getInt() < 0){
                    x = x * cpScalar(-1);
                }
                sum = sum + x;
            }
            return sum;
        }
};

std::ostream& operator<<(std::ostream& s, const cpVector &r) {
            s.put('[');
            if(r.getSize() > 0){
                s << r.getVal(0);
                for (int i = 1; i < r.getSize(); i++) {
                    s << ", " << r.getVal(i);
                }
            }
            return s << ']';
        };

#endif // CPVECTOR_H

cpScalar:

#ifndef CPSCALAR_H
#define CPSCALAR_H
#include <iostream>
#include <string>
#include <cassert>

const int invalid = 99999999;

class cpScalar
{
     private:
        int intData;
        double doubData;
        char dType;

    public:
        cpScalar() {
            intData = invalid;
            doubData = invalid;
            dType = ' ';
        }
        cpScalar(int d) {
            intData = d;
            doubData = invalid;
            dType = 'i';
        }
        cpScalar(double d) {
            intData = invalid;
            doubData = d;
            dType = 'd';
        }

        cpScalar operator+ (cpScalar &s){
            if (getType() == 'i' && s.getType() == 'i'){
                return cpScalar(getInt() + s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() + s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() + s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() + s.getDouble());
            }
            return cpScalar(invalid);
        }

        cpScalar operator/ (cpScalar s){
            assert(s.getDouble() != 0 && s.getInt() != 0);

            if (getType() == 'i' && s.getType() == 'i'){
                if(getInt() % s.getInt() == 0) return cpScalar(getInt() / s.getInt());
                else return cpScalar(1.0 * getInt() / s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() / s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() / s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() / s.getDouble());
            }
            return cpScalar(invalid);
        }

        cpScalar operator* (cpScalar s){
            if (getType() == 'i' && s.getType() == 'i'){
                return cpScalar(getInt() * s.getInt());
            }else if (getType() == 'd' && s.getType() == 'i'){
                return cpScalar(getDouble() * s.getInt());
            }else if (getType() == 'i' && s.getType() == 'd'){
                return cpScalar(getInt() * s.getDouble());
            } else if (getType() == 'd' && s.getType() == 'd'){
                return cpScalar(getDouble() * s.getDouble());
            }
            return cpScalar(invalid);
        }

        friend std::ostream& operator<< (std::ostream &sout, const cpScalar &d);

        int getInt() const{return intData;}

        double getDouble() const{return doubData;}

        char getType() const{return dType;}

};
        std::ostream& operator<<(std::ostream &sout, const cpScalar &d) {
            if(d.getType() == 'i') sout << d.getInt();
            else if (d.getType() == 'd') sout << d.getDouble();
            return sout;
        };
#endif // CPSCALAR_H

谢谢你的阅读

1 回答

  • 0

    您不能存储指向堆栈上分配的临时变量的指针 . 当临时在其范围的末尾不再存在时,指针不再有效 .

    例如,使用以下代码(注意,为简洁起见,我在这些示例中省略了数组值的初始化):

    struct Foo
    {
      int* data;
      Foo( int* d )
      : data( d )
      {
      }
    };
    
    Foo makeFoo( size_t size )
    {
      int bar[ size ]; // note this in invalid c++, only allowed by a gcc extension
      return Foo( bar );
    }
    
    int main()
    {
      Foo f = makeFoo( 4 );
      std::cout << f.data[ 0 ]; // undefined behaviour, f.data points to and array that no longer exists
    }
    

    makeFoo 结束后,数组 bar 不存在,并且返回的 Foodata 指针指向已释放的内存 . 注意,如果运行上面的代码,它可能会打印正确的输出,因为尽管数组不再存在,但是's values won't已被覆盖,因为在打印输出之前没有其他函数会使用该堆栈 .

    这个问题的最C解决方案是使用 std::vector

    struct Foo
    {
      std::vector< int > data;
      Foo( const std::vector< int >& data )
      : data( d ) // make a copy of the temporary vector, no more undefined behaviour
      {
      }
    };
    
    Foo makeFoo( size_t size )
    {
      std::vector< int > bar( size );
      return Foo( bar );
    }
    

    如果你的作业不允许你使用 std::vector (我讨厌试图通过不允许你使用语言和标准库的关键功能来教你C的作业)那么你需要使用指针:

    struct Foo
    {
      int* data;
      Foo( int* d )
      : data( d )
      {
      }
    };
    
    Foo makeFoo( size_t size )
    {
      int* bar = new int[ size ];
      return Foo( bar );
    }
    

    您需要确保实现在数组上调用 delete[] 的析构函数,否则您将发生内存泄漏并记下rule of three并实现或删除复制构造函数和赋值运算符 .

    为了避免这个问题,我们应该使用 std::unique_ptr 为我们删除数组并避免3/5问题的规则:

    struct Foo
    {
        std::unique_ptr< int[] > data;
        Foo(std::unique_ptr< int[] >&& d)
            : data( std::move( d ) )
        {
        }
    };
    
    Foo makeFoo(size_t size)
    {
        std::unique_ptr< int[] > bar( new int[ size ] ); 
        return Foo( std::move( bar ) );
    }
    

    请注意,由于无法复制 std::unique_ptr ,我们必须使用 std::move 来移动值而不是复制它们 . 您还需要使用_32411来移动Foo对象而不是复制它们 . 有关移动对象如何在C中工作的信息,请参阅https://en.cppreference.com/w/cpp/language/move_constructor(初学者可能有点高级但是现代C的一个关键特性) . 如果你无法理解移动物体,你可以使用_32413而不是(只需用上面的例子中的 std::shared_ptr 替换 std::shared_ptr 并删除 std::move ),这是可复制的,但请注意,如果复制 Foo 对象,两个副本都将指向相同的数据 .

相关问题