类内初始化一个该类的实例会引起堆栈溢出的原因分析(害,愚蠢的错误)
#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; }
报错信息如下图所示
经过打断点发现在类在初始化的时候,会调动构造函数,同时会初始化类内的变量,当这个变量是该类时,又会调动构造,然后初始化该对象中的变量,这样就永无休止的调用构造,最终堆栈溢出。
当然,这是一个错误,不过很多时候也会用到这种情况,那就初始化一个该类的指针就完事儿