类内初始化一个该类的实例会引起堆栈溢出的原因分析(害,愚蠢的错误)

#include <iostream>
#include <vector>

using namespace std;

struct Sales_data {

    //友元函数不受权限控制,友元函数的作用就是提供直接访问对象的私有成员的接口。
    friend Sales_data add(const Sales_data&, const Sales_data&);
    friend std::ostream& print(std::ostream&, Sales_data&);
    friend std::istream& read(std::istream&, Sales_data&);

public:
    Sales_data() = default;
    Sales_data(const string &s):bookNo(s){}
    Sales_data(const string& s,unsigned n,double p) :bookNo(s),units_sold(n),revenue(p*n) {}
    Sales_data(std::istream&);

    std::string isbn() const { return bookNo;}
    Sales_data& combine(const Sales_data&);

private:
    double avg_price()const;//const的作用,修改隐式this指针为const,该调用不能修改参数
    
    std::string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};

Sales_data add(const Sales_data&, const Sales_data&);
std::ostream& print(std::ostream&, Sales_data&);
std::istream& read(std::istream&, Sales_data&);

class Screen {
public:
    //typedef std::string::size_type pos;和下一行等价
    using pos = std::string::size_type;
    Screen() = default;//编译器提供默认构造
    Screen(pos ht, pos wd, char c) :height(ht), width(wd),contents(ht * wd,c){}
    char get()const { return contents[cursor]; }//读取光标处的字符,内联
    inline char get(pos ht, pos wd)const;//内联
    Screen& move(pos r,pos c);//可以在之后被设置为内联
    Screen &set(char);
    Screen &set(pos, pos, char);
    Screen& display(ostream& os) { do_display(os); return *this; }//*this指针转为指向常量的指针,do_display之后
    const Screen& display(ostream& os)const { do_display(os); return *this; }//根据os的不同调用常量版本还是非常量版本
private:
    pos cursor = 0;
    pos height = 0, width = 0;
    string contents;
    mutable size_t access_ctr;//即使是const对象内也能被修改
    //std::vector<Screen> screens{ Screen(24,80,' ') };


    //私有函数被公共代码调用的原因:
    //1.避免冗余,2.函数会逐渐复杂,写在同一个地方更加便于操作,3.打印日志方便,4.display调用内联do_display不会增加额外开销
    void do_display(ostream& os)const { os << contents; }
};

class   window_mgr {
private:
    std::vector<Screen> screens{ Screen(24,80,' ') };
};

int main()
{
    Screen myScreen(5, 5, 'X');
    
    myScreen.move(4, 0).set('#').display(cout);
    cout << "\n";
    myScreen.display(cout);
    cout << "\n";
    std::cout << "Hello World!\n";
    
}

double Sales_data::avg_price()const
{
    if (units_sold)
        return revenue / units_sold;
    else
        return 0;

}

Sales_data::Sales_data(std::istream &is)
{
    read(is, *this);
}

Sales_data& Sales_data::combine(const Sales_data& rhs)
{
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}

istream& read(istream &is, Sales_data &item)
{
    double price = 0;
    is >> item.bookNo >> item.units_sold >> price;
    item.revenue = price * item.units_sold;
    return is;
}

ostream& print(ostream &os,Sales_data &item)
{
    os << item.isbn() << " " << item.units_sold << " "
        << item.revenue << " " << item.avg_price();
    return os;
}

Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
    Sales_data sum = lhs;
    sum.combine(rhs);
    return sum;
}

inline char Screen::get(pos r, pos c) const
{
    pos row = r * width;
    return contents[row + c];
}

Screen& Screen::move(pos r, pos c)
{
    pos row = r * width;
    cursor = row + c;
    return *this;
}

Screen& Screen::set(char c)
{
    contents[cursor] = c;
    return *this;
}

Screen& Screen::set(pos r, pos col, char ch)
{
    contents[r * width + col] = col;
    return *this;
}

  报错信息如下图所示

经过打断点发现在类在初始化的时候,会调动构造函数,同时会初始化类内的变量,当这个变量是该类时,又会调动构造,然后初始化该对象中的变量,这样就永无休止的调用构造,最终堆栈溢出。

 当然,这是一个错误,不过很多时候也会用到这种情况,那就初始化一个该类的指针就完事儿

posted @ 2022-01-26 10:58  Smah  阅读(42)  评论(0编辑  收藏  举报