C++Primer 5th Chap7 Classes
this关键字:
在成员函数内部可以直接调用函数的对象的成员(类成员的直接访问看做是对this隐式引用,默认this指向非常量)
例如:string isbn() const{return this->bookNo;}//这里const使得this可以指向常量,此处this指针表示指向“这个”对象(这里this可以省略)
编译器先编译成员的声明,然后编译成员函数体(所以即使类成员声明在函数之后,执行包含该成员的函数仍然可行)
若类的外部定义成员函数,且为常量成员函数,则在参数列表后的const不可省略,且必须包含所属类名:
double Sales_data::avg_price() const{
/*...................*/}
返回this对象的函数:
例如:Sales_data& Sales_data::combine(const Sales_data &rhs){
/*.......................*/
return *this;}
类相关的非成员函数:不声明在类中但是应与类声明在同一头文件中
构造函数:无返回类型,可以在构造过程中给const成员写值,构造函数本身不能声明为const
如果不自己写一个构造函数,系统自动生成一个不含参的默认构造函数(如果类不是那么简单,默认构造函数常常是不堪其用的)
如果自己已经写了构造函数但仍然希望保留系统提供的默认构造函数:Sales_data()=default;(c++11)
构造函数的初始化:
1.初始值列表:Sales_data (const string &s,unsigned n,double p):bookNo(s),units_sold(n),revenue(p*n){ }每个成员对应一个初始值
2.构造函数体:Sales_data (istream &is){
read(is,*this);}//函数体内执行构造, 使用this把对象当做整体访问,这里使用*this将“this”对象作为实参传递给read函数
当类需要分配类对象之外的资源时,默认的合成构造和析构函数不能满足要求(例如需要动态管理内存的程序)
访问控制:
定义在public之后:整个程序内可被访问
定义在private之后:只有类的成员函数能访问该成员
默认struct在第一个定义权限的成员之前的成员是public
默认class在第一个定义权限的成员之前的成员是private(实际上除去此默认权限的区别,struct和class区别不大)
友元(friend):使得其他类或者函数能够访问类的非public成员,只需在该类或函数定义之前加上friend关键字,注意只能出现在类定义的内部
另外,在类之外需要再进行一遍函数声明(这里无需friend),与类保存在同一头文件中
除了数据和函数之外,类也可以自定义某种类型在类中的别名(如果想使用此别名,必须先定义后使用),如:
public(或private): typedef string::size_type st;(或using st=string::size_type)
定义在类内部的成员函数自动inline,也可以在类外部定义时手动inline(在定义处指定inline)
希望在const成员函数内能够修改数据成员:在此数据成员声明处之前加上mutable关键字,这样在const对象中其值仍然可改
例如:mutable size_t ctr;
调用:void MyClass::some_member()const{ ++ctr;}
类内初始值:例如:class Window_mgr{
private:
vector<Screen> screens{Screen(10,20,' ')}; };
返回*this的成员函数:
例如:inline Screen &Screen::set(char c){
contents[cursor]=c;
return *this;}
类成员中允许存在指向类自身的指针和引用:(实际上在学习链表之类的链节点时已经广泛的使用了)
例如:class Link_screen{
/*...............*/
Link_screen *next;
Link_screen *prev;}
类之间的友元:(注意,友元关系不存在传递性,就如朋友的朋友不一定是我的朋友)
例如:class Screen{
friend class Window_mgr;}//这样类Window_mgr中的成员便可以访问类Screen的私有成员了
或者只为类中某个成员函数提供友元权限:
例如:class Screen{
friend void Window_mgr::clear(ScreenIndex);}//这里只为类Window_mgr的clear函数提供了友元权限(注意标明成员所属的类)
(注意:一组重载函数若都想获得友元权限,则必须一个一个提供)
类的成员函数在类外定义时,返回类型若是类中定义的,则要说明此类型归属于此类:Myclass::returnType Myclass::funcName(parameters){/*.....................*/}
若类的作用域内有成员和外部作用域中的成员同名,类中的成员函数调用此名成员时使用的是内部域的成员
若类型名已经在外部作用域中定义过(typedef),在类作用域内不能再重新定义(即使与之前的定义一致)
建议不要将成员名字作为参数或者其他局部变量使用(虽然能用,但是可读性差)
必须使用构造函数初始值列表为const、引用等类型成员提供初始值,成员的初始化顺序只与其定义顺序有关,先定义先初始化(哪怕初始化写在后面)
委托构造函数:(c++11)
委托构造函数使用类中的其他构造函数执行自己的初始化过程
例如:
1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 class Sales_data{ 5 private: 6 string bookNo; 7 unsigned units_sold; 8 double revenue; 9 public: 10 Sales_data(string s,unsigned cnt,double price): 11 bookNo(s),units_sold(cnt),revenue(cnt*price){} 12 Sales_data():Sales_data("",0,0){} 13 Sales_data(string s):Sales_data(s,0,0){} 14 15 16 }; 17 int main(){ 18 return 0; 19 }
这里第一个Sales_data构造函数为其他构造函数提供初始化过程
如果在类内的构造函数前加上关键字explicit,可以抑制隐性的类类型转换,而且只能用列表直接初始化
例如:string null_book="666-66-6666666";
item.combine(null_book);//如果没有explicit的限制,null_book隐性地转换为类Sales_data的对象,调用Sales_data(string s)这一构造函数
item.combine(Sales_data(null_book));//显式构造类对象
item.combine(static_cast<Sales_data>(null_book));//同上
聚合类:
全员public、未定义构造函数、无类内初始值、无基类和虚函数
例如:struct Bind{
string s;
int val;}
Bind bound={"roll",0};//用户初始化值必须<=成员数目,而且初始化顺序要与定义顺序完全一致
字面值常量类:(为了满足数据成员中存在constexpr的要求)
数据类型都是字面值类型的聚合类
或者(非聚合类)类中至少含有一个constexpr构造函数、都是字面值类型、类内初始值使用常量表达式(或者使用自己的constexpr构造函数)、使用析构函数的默认定义
constexpr构造函数:通常是constexpr Myclass()=default;
类的静态成员(声明前面加上static关键字)存在于任何对象之外==>静态成员函数不能定义为const而且不能使用this指针
在调用静态成员时,无需再加上static和对象,只用类作用域符即可:void Myclass::staFunc(int parameter);
注意:静态成员在类的外部定义和初始化(只能一次)(如果是const整数类型的初始值,则可以给类内的constexpr静态成员初始化)
静态成员可以作为默认实参(非静态成员不可)