c++ primer 读书笔记 之第七章类

来源:互联网 发布:2016全国溺水事故数据 编辑:程序博客网 时间:2024/05/16 01:44

只读书不记录总感觉没读,只记录不实践总感觉没记

接口代码例子:

struct Sales_data{        // 以下4个函数都是构造函数Sales_data():units_sold(0), revenue(0.0){ }Sales_data(const std::string &s):            bookNo(s), units_sold(0), revenue(0.0) { }Sales_data(const std::string &s, unsigned n, double p):           bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(std::istream &);//绿色部分初始化列表,没在其中的的成员变量将执行隐式初始化,也就是说,该构造函数体内部其实更像是赋值,而不是初始化// 接口部分的成员函数,定义在类内部的函数都是隐式的inline函数std::string isbn() const { return bookNo; }//1、inline 函数;2、同时又是常量成员函数 ;3、成员函数体内可以随意适用其他成员变量或者成员函数,无需                                                      在意声明的次序,因编译类时首先是编译成员的声明,然后才是成员函数体Sales_data& combine(const Sales_data&);double avg_price() const;std::string bookNo;unsigned units_sold;double revenue;};// 接口部分的非成员函数,想一想这些函数的调用者是对象吗?如果非成员函数是类接口的一部分,则这些函数的声明应该与类在同一个头文件内Sales_data add(const Sales_data&, const Sales_data&);std::ostream &print(std::ostream&, const Sales_data&);std::istream &read(std::istream&, Sales_data&);
上面的代码就是一个接口         

                                                                                                                                                                                                                                                            

double Sales_data::avg_price() const {if (units_sold)return revenue/units_sold;elsereturn 0;}// Sales_data& Sales_data::combine(const Sales_data &rhs) //返回值是变量的引用类型,就可<左值>返回。{units_sold += rhs.units_sold; // add the members of rhs into revenue += rhs.revenue;       // the members of ``this'' objectreturn *this; // return the object on which the function was called}

上面的代码是在类外部定义成员函数

Sales_data add(const Sales_data &lhs, const Sales_data &rhs){Sales_data sum = lhs;  // copy data members from lhs into sumsum.combine(rhs);      // add data members from rhs into sumreturn sum;}// transactions contain ISBN, number of copies sold, and sales priceistream& read(istream &is, Sales_data &item)//同常我们为了避免copy值传递的效率低下,适用引用来作为形参,这是一种<优化技巧>但对于io类型的形参来说则是必                                        须,因为io类型的变量无copy类型{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;}Sales_data::Sales_data(std::istream &is) {// read will read a transaction from is into this objectread(is, *this);//先声明一下,this是一个指针,见<c++ primer>p231用请求该函数的对象地址来初始化this,以及this->bookNo。明白了所以*就是一个正常的普                           通对象变量,为什么这里的实参是一个变量,而形参可以看到是一个引用。这就涉及到<函数胡形参>}
inline函数适用条件:1.规模较小(能够在类内定义估计也不能太大);2.直接;3.重复使用(inline函数效率高,可以作为一种优化技巧)隐式inlien:定义在类内部胡函数;显式inline关键字inlie可以加在函数声明胡地方,也可以加在函数定义的地方,或者两者同时加,也不错。但一般是定义。还有就是inline函数的定义及时不能定义在类内,一般也要建议定义在头文件内。常量成员函数为了c++程序的健壮性。对于调用自身对象成员变量或者成员函数的成员函数,都应该声明为常量成员函数。因为对于这类成员函数,都隐式或者显式的适用。this来指代自身对象,自身对象有可能是常量对象也有可能是非常量对象,const来修饰this就可以做到万无一失。但是常量成员函数有一个缺点:在该函数内无法修改对象的成员变量,因为对象是const。下文提到的可变成员变量可以解决这一问题。对于即使在常量成员函数中你也想改变的成员变量,可以把它声明为mutable(可变成员变量)左值可以放在等号的左侧被赋值的值即为左值。(1)(a=1)=2  ok    a=1=2 不ok。式子1是因为=源码返回的是一个引用(不信可以去看),所以可以作为左值。而式子2不行是因为c++中的赋值运算满足右结合律。构造函数只有当类没有声明任何构造函数时,编译器才会自动的生成默认构造函数。当然用户自己定义的构造函数也可以是默认构造函数。函数的传参

c++中,函数的传参只有两种值传递和引用传递(没错是没有指针这么一说的,但指针传递是划分为值传递中的)

 A、 值传递(感觉称之为copy传递更好):普通变量值传递1、变量定义 int a=1;2、函数声明 int f(int val);3、                                                                           函数调用 f(a);

                                                                        指针变量值传递 1、变量定义 int a=1;  2、函数声明 int f(int *                                                                                  val);3、函数调用f(&a)

B、引用传递:1、变量定义 int a=1;2、函数声明 int f(int & val);3、函数调用f(a)

总结:引用传递会带来两个方面的影响。1不用copy一份变量,节省时间和内存;2.是可以通过函数来改变实参。如果函数无须改变引用形参的值,最好将其声明为const,这样好像立了一个法,从法律上规定在函数体内部改变实参是违法的,让函数的使用者一目了然更加放心。为了软件的优化,会看到c++程序中(常量)引用漫天飞舞

符:引用还有一个技巧:当希望程序返回多于两个值时,一:用类等较复杂的抽象数据类型;二:将多于的返回值以引用的形式输入,同时获得。

   

上面代码阐述完毕,看下面一段代码:

class Sales_data {//改动1friend Sales_data add(const Sales_data&, const Sales_data&);//改动3friend std::ostream &print(std::ostream&, const Sales_data&);//改动3friend std::istream &read(std::istream&, Sales_data&);//改动3public: //改动2// constructorsSales_data(): units_sold(0), revenue(0.0) { }Sales_data(const std::string &s):            bookNo(s), units_sold(0), revenue(0.0) { }Sales_data(const std::string &s, unsigned n, double p):           bookNo(s), units_sold(n), revenue(p*n) { }Sales_data(std::istream &);// operations on Sales_data objectsstd::string isbn() const { return bookNo; }Sales_data& combine(const Sales_data&);double avg_price() const;private: //改动2std::string bookNo;unsigned units_sold;double revenue;};// nonmember Sales_data interface functionsSales_data add(const Sales_data&, const Sales_data&);std::ostream &print(std::ostream&, const Sales_data&);std::istream &read(std::istream&, Sales_data&);// used in future chaptersinline bool compareIsbn(const Sales_data &lhs, const Sales_data &rhs){return lhs.isbn() < rhs.isbn();}
上述代码与之前版本代码在大部分不变的情况下,有如下小的改动:

改动1:类的定义由struct 取代为class。两者唯一的区别是:struct的默认访问权限为public,class为private(更安全有没有)

改动2:构造函数和部分类内函数的访问说明符为public(整个程序都可访问);类内成员变量的访问说明符为private(类内可访问)。这就是c++的封装通过访问说明符来实现                 这一机制。 

改动3:有了改动2,那么其他想访问类内private变量的方法,怎么办呢?最直接的是最初版本代码中的add,print,read,(我们可是团结合作来实现一个接口的,连我都不不能信息             共享了),有两种方法,一种是类针对all想访问private的用户设计一个public函数,get_xx,set_xx。但在这些函数内部加以限制和判断。第二种方法是专门为朋友开后门,               也即友元。住:类内的friend声明仅仅是给类看的,类外还需正常的函数声明。类内友元声明,并不表明友元函数式类内函数。

类型成员给类型起别名:方式1:typedef std::string::size_type pos
                            方式2:using pos=std::string::size_type
类型成员作为类成员的一种也是有访问修饰符public和private的。并且也注意:类型成员的定义必须位于使用之前重载成员函数成员函数参数的数量和类型有区别即可。可变数据成员见上文中的常量成员函数返回*this的成员函数

c++编程规则1:return *this,一般与函数声明中返回对象引用同时使用。
有两个优点:1返回引用的函数是左值的见上文左值;
                      2返回的是对象本身而非副本  从而myScreen.move(4,0).set("#")两次函数操作操作的同一个对象myScreen
如果函数的返回类型不是引用,myScReen.move(4.0).set("#")执行完毕实质上对于myScReen对象本身仅仅操作了move,而set操作是针对于myScReen的副本,原因见函数是如何返回的
函数是如何返回的画重点,函数返回的值用于初始化调用点的一个临时变量。如果该临时变量是一个引用变量,则临时变量就是返回值本身。如果不是引用变量,就是返回值的一个副本c++编程规则2
对于公共代码使用私有功能函数。
优点:1.节省代码量
           2.功能修改方便,只需修改一处
           3.类内定义,隐式inline并不耗费时间。
类内定义类成员
a.可以声明自身类型的引用,或者指针(数据结构中链表Node不就是这么干的嘛);不可以定义自身类型的变量,因为类大小未知

      



原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 宝宝不爱吃饭怎么办吃就吐出来 19天的宝宝生理性腹泻怎么办 33天的婴儿生理性腹泻怎么办 两个多月宝宝生理性腹泻怎么办 3岁儿童又吐又拉怎么办 宝宝两岁了突然说话有点口吃怎么办 姜文怎么克服口吃 说话结巴怎么办 慢性咽炎嗓子干哑说话费劲怎么办 感冒后嗓子不疼 说话费劲怎么办 小孩子在幼儿园内向老尿裤子怎么办 五岁宝宝总是抽鼻子有黄鼻涕怎么办 2岁宝宝头有大人的那么大怎么办 一岁四个月宝宝不理人不说话怎么办 两岁七个月还不会说话怎么办 2岁3个月宝宝说话结巴怎么办 两周的宝宝突然说话结巴怎么办 宝宝3岁半了说话口吃怎么办? 四十天的宝宝吐奶严重怎么办 宝宝吐奶从鼻子喷出来怎么办 六个多月宝宝吐奶一股酸味怎么办 50天的宝宝吃了就吐怎么办 微信语音群聊超过9人怎么办 四个月宝宝母乳不够不喝奶粉怎么办 四个月的宝宝母乳不够吃怎么办 火山直播十多天了还都是假人怎么办 吉利汽车锁了后屁股灯还亮怎么办 六个月凶了他突然不说话了怎么办 微信聊天聊的时间长了没话题怎么办 群聊同学加我微信不想加怎么办? 翡翠销售遇到不说话的客人怎么办 4个月宝宝吃手上瘾怎么办 宝宝吃手上瘾拒绝吃奶粉吃奶怎么办 2岁宝宝特别粘人爱哭怎么办 3岁半宝宝突然说话口吃怎么办 2岁3个月宝宝突然说话结巴怎么办 一位特爱说话爱玩的高中生怎么办 猫5天不吃不喝躲起来该怎么办 两个月的小家猫睡觉要黏人睡怎么办 成年的儿子不听话做父母要怎么办 听到孩子上课又不听话想揍他怎么办 18个月小孩脾气很犟怎么办