1.类的基本思想是数据抽象和封装。
2.只有类的非静态成员才有this指针。成员函数通过一个名为this的额外的隐式参数来访问它的那个对象。当我们调用一个成员函数时,用请求该函数的对象地址初始化this。任何对类成员的直接访问都被看作this的隐式引用。
定义一个返回this对象的函数
Sales_data& Sales_data::combine(const Sales_data& rhs)
{
units_sold+=rhs.units_sold; //把rhs的成员加到this对象的成员上
revenue+=rhs.revenue;
return* this; //返回调用该函数的对象
}
total.combine(trans); //类似于+=
3.每个类都分别定义了它的对象被初始化的方式,类通过一个或几个特殊的成员函数来控制其对象的初始化过程,这些函数叫做构造函数。构造函数的任务是初始化类对象的数据成员,无论何时只要类的对象被创建,就会执行构造函数。构造函数可以重载,构造函数应该使用构造函数初始值列表初始化所有数据成员。
在参数列表后面写上=default来要求编译器生成默认构造函数。
4.访问说明符加强了类的封装:
①.定义在public说明符之后的成员在整个程序内可被访问,public成员定义类的接口。
②.定义在private说明符之后的成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了类的实现细节。
使用class和struct定义类唯一的区别是默认的访问权限。class默认是private,struct默认是public。
5.类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元,只需要增加一条以friend关键字开始的函数声明即可。友元关系不存在传递关系,每个类负责控制自己的友元类或友元函数。
友元声明只能出现在类定义的内部,友元不是类的成员也不受它所在默认区域访问控制级别的约束。
友元函数在使用之前最好在类的外部(头文件内)提供一个独立的函数声明。
6.可变数据成员:在变量的声明前加入mutable关键字,一个可变数据成员永远不会是const,即使它是const对象的成员。
7.构造函数初始化和赋值事关底层效率问题,而且一些数据成员必须被初始化。
class ConstRef()
{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri; //常量对象和引用成员必须被初始化
}
ConstRef::ConstRef(int i): i(ii), ci(ii), ri(i) {} //初始化
成员初始化顺序与它们在类定义中的出现顺序一致,构造函数初始值列表只说明用于初始化成员的值,而不限定初始化的具体执行顺序。
8.能通过一个实参调用的构造函数定义了一条从构造函数的参数类型向类类型隐式转换的规则:
① 编译器只会自动地执行一步类型转换。
Sales_data item;
item.combine("9-999-99999-9"); //错误的,“9-999-99999-9”->string->Sales_data
//正确形式:
item.combine(string("9-999-99999-9"));
item.combine(Sales_data("9-999-99999-9"));
②类类型转换不是总有效。
③在要求隐式转换的程序上下文中,我们可以通过将构造函数声明为explicit加以阻止。
关键字explicit只对一个实参的构造函数有效。
只能在类内声明构造函数时使用explicit关键字,在类外部定义时不应重复。
explicit构造函数只能用于直接初始化。
9.聚合类:使得用户可以直接访问其成员,并且具有特殊的初始化语法形式。
满足以下几个条件:
①.所有成员都是public的。
②.没有定义任何构造函数。
③.没有类内初始值。
④.没有基类,也没有virtual函数。
struct Data{
int ival;
string s;
};
10.字面值常量类:数据成员都是字面值类型的聚合类是字面值常量类。
或者满足以下要求:
① 数据成员都必须是字面值类型。
② 类必须至少含有一个constexper构造函数。
③ 如果一个数据成员含有类内初始值,则内置类型成员的初始值必须是一条常量表达式;或者如果成员属于某种类类型,则初始值必须使用成员自己的constexper构造函数。
④ 类必须使用析构函数的默认定义,该成员负责销毁类的对象。
class Debug{
public:
constexper Debug(bool b=true):hw(b),io(b),other(b) {}
constexper Debug(bool h,bool i,bool o):hw(h),io(i),other(o) {}
constexper bool any() {return hw || io || other;}
void set_io(bool b) {io=b;}
void set_hw(bool b) {hw=b;}
void set_other(bool b) {other=b;}
private:
bool hw; //硬件错误
bool io; //io错误
bool other; //其他错误
};
11.类的静态成员:我们通过在成员的声明之前加上关键字static使得其与类关联在一起。
类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。
静态成员函数也不与任何对象绑定在一起,它们不包含this指针。作为结果,静态成员函数布恩那个声明为const的,而且我们也不能在static函数体内使用this指针。
成员函数不用通过作用域运算符就能直接使用静态成员。
静态数据成员定义在任何函数之外,一旦被定义就一直存在于程序的整个生命周期中。
静态成员和普通数据成员的区别:
① 静态数据成员的类型可以就是它所属的类类型,而非静态数据成员只能声明成它所属类的指针或引用。
class Bar{
public:
//....
private:
static Bar mem1;
Bar *mem2;
Bar mem3; //错误
};
② 我们可以使用静态成员作为默认实参。