C++Primer_第7章_类
来源:互联网 发布:ubuntu 16.04安装qq 编辑:程序博客网 时间:2024/05/20 09:49
7.1结构体
struct Sales_data {Sales_data() = default;Sales_data(const std::string &s):bookNo(s){}Sales_data(const std::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&);double avg_price()const;std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};
=default的含义
构造函数不能被声明成const的。
Under the new standard, if we want the default behavior, we can ask the compiler to generate the constructor for us by writing = default after the parameter list.
构造函数初始值列表
Sales_data(const std::string &s):bookNo(s){}Sales_data(const std::string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){}
花括号定义了(空的)函数体,冒号和花括号之间的部分称为构造函数初始值列表(constructor
initializer list),它负责为新创建的对象的一个或几个数据成员赋初值。括号括起来的是成员初值。
initializer list),它负责为新创建的对象的一个或几个数据成员赋初值。括号括起来的是成员初值。
在类的外部定义构造函数
Sales_data::Sales_data(std::istream &is){read(is, *this);//read函数的作用是从is中读取一条交易信息然后存入this对象中}
练习7.11在你的Sales_data类中添加构造函数,然后编写一段程序令其用到每个构造函数。
#ifndef CP5_ex7_11_h#define CP5_ex7_11_h#include <iostream>#include <string>// Add constructors to your Sales_data classstruct Sales_data {Sales_data() = default;Sales_data(const std::string& s) : bookNo(s) {}Sales_data(const std::string& s, unsigned n, double p): bookNo(s), units_sold(n), revenue(n * p){}Sales_data(std::istream& is);std::string isbn() const { return bookNo; };Sales_data& combine(const Sales_data&);std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};// nonmember functionsstd::istream& read(std::istream& is, Sales_data& item){double price = 0;is >> item.bookNo >> item.units_sold >> price;item.revenue = price * item.units_sold;return is;}std::ostream& print(std::ostream& os, const Sales_data& item){os << item.isbn() << " " << item.units_sold << " " << item.revenue;return os;}Sales_data add(const Sales_data& lhs, const Sales_data& rhs){Sales_data sum = lhs;sum.combine(rhs);return sum;}// member functions.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;}#endif
#include "ex7_11_sales_data.h"int main(){ Sales_data item1; print(std::cout, item1) << std::endl; Sales_data item2("0-201-78345-X"); print(std::cout, item2) << std::endl; Sales_data item3("0-201-78345-X", 3, 20.00); print(std::cout, item3) << std::endl; Sales_data item4(std::cin); print(std::cout, item4) << std::endl;}练习7.12:把只接受一个istream作为参数的构造函数定义移到类的内部。
#ifndef CP5_ex7_12_h#define CP5_ex7_12_h#include <iostream>#include <string>struct Sales_data;std::istream& read(std::istream&, Sales_data&);struct Sales_data {Sales_data() = default;Sales_data(const std::string& s) : bookNo(s) {}Sales_data(const std::string& s, unsigned n, double p): bookNo(s), units_sold(n), revenue(n * p){}// Move the definition of the Sales_data constructor that takes an istream into// the body of the Sales_data class.Sales_data(std::istream& is) { read(is, *this); }std::string isbn() const { return bookNo; };Sales_data& combine(const Sales_data&);std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){units_sold += rhs.units_sold;revenue += rhs.revenue;return *this;}// nonmember functionsstd::istream& read(std::istream& is, Sales_data& item){double price = 0;is >> item.bookNo >> item.units_sold >> price;item.revenue = price * item.units_sold;return is;}std::ostream& print(std::ostream& os, const Sales_data& item){os << item.isbn() << " " << item.units_sold << " " << item.revenue;return os;}Sales_data add(const Sales_data& lhs, const Sales_data& rhs){Sales_data sum = lhs;sum.combine(rhs);return sum;}#endif练习7.13:使用istream构造函数重写第229页的程序。
#include "CP5_ex7_12.h"int main(){Sales_data total(std::cin);if (!total.isbn().empty()) {std::istream& is = std::cin;while (is) {Sales_data trans(is);if (total.isbn() == trans.isbn())total.combine(trans);else {print(std::cout, total) << std::endl;total = trans;}}}else {std::cerr << "No data?!" << std::endl;return -1;}return 0;}
拷贝、赋值和析构Copy, Assignment, and Destruction
In addition to defining how objects of the class type are initialized, classes also control what happens when we copy, assign, or destroy objects of the class type.
Although the compiler will synthesize the copy, assignment, and destruction operations for us, it is important to understand that for some classes the default versions do not behave appropriately. In particular, the synthesized versions are unlikely to work correctly for classes that allocate resources that reside outside the class objects themselves. As one example, in Chapter 12 we’ll see how C++ programs allocate and manage dynamic memory. As we’ll see in § 13.1.4 , classes that manage dynamic memory, generally cannot rely on the synthesized versions of these operations.However, it is worth noting that many classes that need dynamic memory can (and generally should) use a vector or a string to manage the necessary storage.Classes that use vectors and strings avoid the complexities involved in allocating and deallocating memory.
访问控制与封装Access Control and Encapsulation
Members defined after a public specifier are accessible to all parts of the program. The public members define the interface to the class.
Members defined after a private specifier are accessible to the member functions of the class but are not accessible to code that uses the class. The private sections encapsulate (i.e., hide) the implementation.
Members defined after a private specifier are accessible to the member functions of the class but are not accessible to code that uses the class. The private sections encapsulate (i.e., hide) the implementation.
class Sales_data {public: // access specifier addedSales_data() = default;Sales_data(const std::string &s, unsigned n, double p):bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(const std::string &s): bookNo(s) { }Sales_data(std::istream&);std::string isbn() const { return bookNo; }Sales_data &combine(const Sales_data&);private: // access specifier addeddouble avg_price() const{ return units_sold ? revenue/units_sold : 0; }std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};Warning! The only difference between using class and usingstruct to define a class is the default access level. (class : private, struct : public)
出于统一编程风格的考虑,当我们希望定义的类的所有成员是public的时,使用struct;
反之,如果希望成员是private的,使用class。
友元 Friends
A class can allow another class or function to access its nonpublic members by making that class or function a friend.//类可以允许其他类或函数访问它的非公有成员,方法是前面加friend的声明
//友元不存在传递性
class Sales_data {// friend declarations for nonmember Sales_data operations added//为Sales_data的非成员函数所做的友元声明friend Sales_data add(const Sales_data&, const Sales_data&);friend std::istream &read(std::istream&, Sales_data&);friend std::ostream &print(std::ostream&, const Sales_data&);// other members and access specifiers as before其他成员及访问说明符与之前一致public:Sales_data() = default;Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(const std::string &s) : bookNo(s) { }Sales_data(std::istream&);std::string isbn() const { return bookNo; }Sales_data &combine(const Sales_data&);private:std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};// declarations for nonmember parts of the Sales_data interface//Sales_data接口的非成员 组成部分的声明Sales_data add(const Sales_data&, const Sales_data&);std::istream &read(std::istream&, Sales_data&);std::ostream &print(std::ostream&, const Sales_data&);友元声明只能出现在类定义的内部,但是在类内出现的具体位置不限。
Friend declarations may appear only inside a class definition; they may appear anywhere in the class.
Tip. Ordinarily it is a good idea to group friend declarations together at the beginning or end of the class definition.一般来说,最好在类定义开始或结束前的位置集中声明友元。
Tip. Ordinarily it is a good idea to group friend declarations together at the beginning or end of the class definition.一般来说,最好在类定义开始或结束前的位置集中声明友元。
练习7.20:When are friends useful? Discuss the pros and cons of using friends.
friend
is a mechanism by which a class grants access to its nonpublic members. They have the same rights as members.
Pros:
- the useful functions can refer to class members in the class scope without needing to explicitly prefix them with the class name.
- you can access all the nonpublic members conveniently.
- sometimes, more readable to the users of class.
Cons:
- lessens encapsulation and therefore maintainability.
- code verbosity, declarations inside the class, outside the class.
#ifndef CP5_ex7_12_h#define CP5_ex7_12_h#include <iostream>#include <string>struct Sales_data;std::istream& read(std::istream&, Sales_data&);class Sales_data {friend std::istream& read(std::istream& is, Sales_data& item);friend std::ostream& print(std::ostream& os, const Sales_data& item);friend Sales_data add(const Sales_data& lhs, const Sales_data& rhs);public:Sales_data() = default;Sales_data(const std::string& s) : bookNo(s) {}Sales_data(const std::string& s, unsigned n, double p): bookNo(s), units_sold(n), revenue(n * p){}// Move the definition of the Sales_data constructor that takes an istream into// the body of the Sales_data class.Sales_data(std::istream& is) { read(is, *this); }std::string isbn() const { return bookNo; };Sales_data& combine(const Sales_data&);private:std::string bookNo;unsigned units_sold = 0;double revenue = 0.0;};// member functions.Sales_data& Sales_data::combine(const Sales_data& rhs){units_sold += rhs.units_sold;revenue += rhs.revenue;return *this;}// nonmember functionsstd::istream& read(std::istream& is, Sales_data& item){double price = 0;is >> item.bookNo >> item.units_sold >> price;item.revenue = price * item.units_sold;return is;}std::ostream& print(std::ostream& os, const Sales_data& item){os << item.isbn() << " " << item.units_sold << " " << item.revenue;return os;}Sales_data add(const Sales_data& lhs, const Sales_data& rhs){Sales_data sum = lhs;sum.combine(rhs);return sum;}#endif
类成员再探
typedef std::string::size_type pos;//alternative way to declare a type member using a type aliasusing pos = std::string::size_type;//使用类型别名等价地声明一个类型名字
7.5构造函数再探
如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始值列表为这些成员提供初值。在很多类中,初始化和赋值的区别事关底层效率问题:前者直接初始化数据成员,后者则先初始化再赋值。建议读者养成使用构造函数初始值的习惯,这样能避免某些意想不到的编译错误。
委托构造函数:
class Book_{public:Book_() = default;Book_(unsigned no,std::string name,std::string author,std::string pubdate):no_(no),name_(name),author_(author),pub_date_(pubdate){}Book_(std::istream &in) { in >> no_ >> name_ >> author_ >> pub_date_; }private:unsigned no_;std::string name_;std::string author_;std::string pub_date_;};//使用委托构造函数class Book {public:Book(unsigned no, std::string name, std::string author, std::string pubdate) :no_(no), name_(name), author_(author), pubdate_(pubdate) { }Book() : Book(0, "", "", "") { }Book(std::istream &in) : Book() { in >> no_ >> name_ >> author_ >> pubdate_; }private:unsigned no_;std::string name_;std::string author_;std::string pubdate_;};
阅读全文
0 0
- C++Primer_第7章_类
- C++Primer_第11章_关联容器
- C++Primer_第13章_拷贝控制
- C++primer_第七章_类_学习跟踪
- C++primer_第四章_表达式_学习跟踪
- C++primer_第五章_语句_学习跟踪
- C++primer_第六章_函数_学习跟踪
- C++primer_第九章_顺序容器_学习跟踪
- C++primer_第八章_IO库_学习跟踪
- c++primer_类
- C++Primer_笔记_异常处理
- (笔记)c++primer_第一章
- .第04章 CORE C++_指针(II)_动态内存_引用_类_对象_构造函数_析构函数
- C++primer_拷贝控制之13.26联系控制成员实现类值行为
- C++primer_顺序容器之string操作
- C++primer_关联容器之map
- c++primer_第二部分学习的感觉
- C++Primer_范围for处理多维数组
- 操作系统性能监控
- 【原创】数论模板-拓展欧几里得,质因数分解,快速幂快速加,欧拉函数筛法,欧拉函数求法,筛质数,卡塔兰数,筛逆元,第一二类斯特林数,米勒罗宾算法
- linux中shell的小括号、大括号的用法区别
- StringBuffer的常用方法
- 10月24 日 c语言 计算1至10之间奇数之和及偶数之和。
- C++Primer_第7章_类
- app monkey压力测试流程
- 用户注册
- Swift表示分数
- Mybatis学习(05)-mapper代理方法开发dao && 输入映射和输出映射
- 数据结构实验之栈与队列十:走迷宫
- UOJ#6 NOI-2014 随机数生成器
- 【基础算法】有重复元素的全排列问题
- 时间格式转换