【c++ primer, 5e】构造函数 & 拷贝、赋值和析构
【构造函数】
1、构造器就是创建对象时被调用的代码。
2、如果没有自定义构造器,那么编译器将自动合成一个默认的无参构造器。
3、自定义的构造器不允许加const,所创建const的对象只有在构造器代码执行完后,才被赋予const性质。
4、如果自定义了构造器,那么默认的构造器将无效化,可以理解为自定义内容覆盖了默认的内容。—— “要么什么都不做,要么全部都交给你来做。”
5、构造函数使用类内初始值并不是一个坏选择。
6、default。(在练习中体现)
7、构造函数初始值列表。(在练习中体现)
练习
7.11
ps:定义在类内的函数默认为内联的!类外的不是。(内联函数可以提高性能,那么,为什么不把所有函数都定义成内联函数呢?内联函数的优缺点)
#include <iostream> #include <string> using namespace std; // Sales_data.h struct Sales_data { // 新增的构造函数 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(istream&); // public部分,对象看起来是怎么样的。 std::string isbn() const { return bookNo; } // inline function Sales_data& combine(const Sales_data&); double avg_price() const; // private部分,数据成员。 std::string bookNo; unsigned units_sold = 0; double revenue = 0.0; }; // Sales_data的非成员接口函数 Sales_data add(const Sales_data&, const Sales_data&); std::ostream &print(std::ostream&, const Sales_data&); std::istream &read(std::istream&, Sales_data&); // Sales_data.cpp 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, const Sales_data &item) { os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price(); return os; } double Sales_data::avg_price() const { if (units_sold) return revenue/units_sold; else return 0; } Sales_data add(const Sales_data &lhs, const Sales_data &rhs) { Sales_data sum = lhs; sum.combine(rhs); return sum; } Sales_data::Sales_data(istream &is) { read(is, *this); } // main.cpp int main() { Sales_data data1; // default Sales_data data2("ISOD233"); Sales_data data3("ISOD233", 3, 22.5); Sales_data data4(cin); print(cout, data1) << endl; print(cout, data2) << endl; print(cout, data3) << endl; print(cout, data4) << endl; /* output: 0 0 0 ISOD233 0 0 0 ISOD233 3 67.5 22.5 DASD23 4 88 22 */ return 0; }
7.12
就知道这题有坑。
prog1.cpp: In constructor 'Sales_data::Sales_data(std::istream&)': prog1.cpp:13:17: error: 'read' was not declared in this scope read(is, *this);
翻了一下收藏的博客,发现这道题要用友元函数(下一小节)。
7.13
参考(不会写)。
Sales_data total(cin); if (total.units_sold > 0) { Sales_data trans; while (read(cin, trans)) { if (total.isbn() == trans.isbn()) total.combine(trans); else { print(cout, total) << endl; total = trans; } } print(cout, total) << endl; } else { cerr << "No data?!" << endl; }
7.14
是这样吗?
Sales_data() { units_sold = 0; revenue = 0.0; }
7.15
测试无误。
// constructor Person() = default; Person(const string &name): name(name) {} Person(const string &name, const string &address): name(name), address(address) {} Person(istream&);
Person::Person(istream &is) { read(is, *this); }
【拷贝、赋值和析构】
如果我们不主动定义这些操作,那么编译器将会替我们合成它们。
默认的析构函数将会在语句块结束时被调用,销毁局部变量。
某些类(管理动态内存的类)不能依赖于合成的版本,因此有时候不得不定义这些函数。