您的位置:首页 > 编程语言 > C语言/C++

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

2017-06-25 14:40 204 查看
只读书不记录总感觉没读,只记录不实践总感觉没记

接口代码例子:

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;
else
return 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'' object
return *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 sum
sum.combine(rhs);      // add data members from rhs into sum
return sum;
}

// transactions contain ISBN, number of copies sold, and sales price
istream& 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 object
read(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 {//改动1
friend Sales_data add(const Sales_data&, const Sales_data&);//改动3
friend std::ostream &print(std::ostream&, const Sales_data&);//改动3
friend std::istream &read(std::istream&, Sales_data&);//改动3

public: //改动2
// constructors
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 &);

// operations on Sales_data objects
std::string isbn() const { return bookNo; }
Sales_data& combine(const Sales_data&);
double avg_price() const;
private: //改动2
std::string bookNo;
unsigned units_sold;
double revenue;
};

// nonmember Sales_data interface functions
Sales_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 chapters
inline
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不就是这么干的嘛);不可以定义自身类型的变量,因为类大小未知

  
  
  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c++primer