数据抽象与封装
类的public成员实现类的抽象视图,而private成员实现了类的封装;
在左花括号之后、第一个访问标号之前定义的成员:若类用struct定义,则是公有public;若用class定义,则这些成员是私有的private.
不完全类型:只声明一个类而不定义。(class screen;)
不完全类型的使用:不能定义该类型的对象,只能用于定义指向该类型的指针及引用,或者用于声明使用该类型作为形参类型或返回类型的函数。
注:this指针默认是一个指向类类型的const指针
构造函数初始化列表:
可以显示初始化列表,也可以在函数体中对数据成员赋值;
Eg: sales_item::sales_item(string&book):isbn(book),units_sold(0),revenue(0) {}
等价于sales_item::sales_item(string &book)
{isbn=book; units_sold=0; revenue=0;}
注:第二个构造函数分为两个阶段:首先初始化变量为默认值,然后此值被函数体内的赋值所覆盖。
必须使用初始化列表的情况:
没有默认构造函数的类类型的成员,以及const成员或引用类型的成员,因为赋值对他们不起作用,都必须在初始化列表中进行初始化。
Eg: class constref
{public:
constref(int ii);
private:
int i;
const int ci;
int &ri;}
constref::constref(intii)
{i=ii;
ci=ii; //错误,const对象不能进行赋值
ri=ii; //错误,引用必须在定义时初始化
}
所以构造函数应修改为:constref::constref(int ii):i(ii),ci(ii),ri(ii) {}
注意:初始化列表对成员初始化的次序是成员定义的次序 ,应尽量避免使用成员来初始化另一个成员。默认构造函数
只要定义一个对象时没有提供初始化,就是用默认构造函数,为所有形参提供默认实参的构造函数也定义了默认构造函数。
合成的默认构造函数使用与变量初始化相同的规则来初始化成员:类类型的成员通过运行各自的默认构造函数进行初始化,内置类型和复合类型只有在全局作用域才可以进行初始化。
隐式类类型转换:
可以用单个实参来调用的构造函数 定义了从形参类型到该类类型的一个隐式转换。
eg: class sales_item{
public:
sales_item(const string& book=" "):isbn(book),units_sold(0),revenue(0.0) {}
sales_item(istream& is);
//其他成员函数...
private:
string isbn;
int units_sold;
double revenue ;
}
string null_book="9-999-99999-9";
item.same_isbn(null_book);//ok,same_isbn函数期待一个sales_item对象作为实参,在这里编译器使用接受一个string的sales_item构造
//函数从null_book生成一个sales_item对象(临时的),然后将新生成的对象传递给same_isbn函数。
item.same_isbn(cin);//原理同上
若要抑制由构造函数 定义的隐式转换,可以通过将构造函数声明为explicit;
注意:explicit关键字只能用于类内部的构造声明上,在类的定义体外部所做的定义不再重复。
声明为explicit 后,上述两个命令就不能编译。
显式使用构造函数来实现转换:
将上述命令修改为: item.same_isbn(sales_item(null_book));或者item.same_isbn(sales_item(cin));
一般把构造函数声明为explicit可以避免错误(语义上的错误),并且在需要转换时可以显式的构造对象。
类成员的显式初始化:只有未定义构造函数且成员全部为公有时才可以使用显式初始化。
eg:
struct ss
{
int i;
char c;
}
ss s1={2,'a'}; //显式初始化