成员函数
在类内部,声明成员函数是必须的,而要定义成员函数则是可选的。在类内部定义的函数默认都是inline
double avg() const; const成员不能改变其所操作的对象的数据成员。const必须同时出现在声明和定义中,若只出现在一处就会出现一个编译时错误。
在类的外部使用类作用域操作符访问函数,只能访问类的public static成员函数。
如
class Sales_item
{
public:
static double avg_price();
};
在类外部就可以通过Sales_item::avg_price()来访问avg_price函数。
具体类型和抽象类型
并非所有类型都必须是抽象的,标准库中的pair类就不是抽象类。具体类会暴露而非隐藏其实现细节。
显示指定inline成员函数
当inline成员函数被调用时,编译器将试图在同一行内扩展该函数。可以在类定义体内部指定一个成员为inline,作为其声明的一部分。也可以在类定义体外部的函数定义上指定inline。在声明和定义出指定inline都是合法的。
注意:像其他inline一样,inline成员函数的定义必须在调用该函数的每个源文件中是可见的。不在类定义体内定义的inline成员函数,其定义通常应放在有类定义的同一头文件中。
类声明与类定义
在创建类的对象之前,必须完整地定义该类。这样编译器就会给类的对象预定相应的存储空间。
类不能具有自身类型的数据成员,但是类的数据成员可以是指向自身类型的指针或引用。
类对象
一旦定义了类,就可以定义该类型的对象。定义对象时将为其分配存储空间,但定义类型时不进行存储分配。
类的定义以分号结束。分号是必须的,因为在类定义之后可以接一个对象定义列表。如class Sales_item { } aa;
this指针
在普通的非const成员函数中,this的类型是一个指向类类型的const指针。可以改变this所指向的值,但不能改变this所保存的地址。在const成员函数中,this的类型是一个指向const类类型对象的const指针。
可以基于const进行重载,定义两个同名的成员函数,一个味const,另一个非const。
可变数据成员
可变数据成员不能为const。const成员函数可以修改mutable成员。如
class A
{
private:
mutable int a;
public:
void show() const { a++; cout <<a<<endl;}
};
类作用域
形参表和函数体处于类作用域中。
函数返回类型不一定在类作用域中。如果在类定义体之外定义,则用于返回类型的名字在类作用域之外。如果返回类型使用由类定义的类型,则必须使用完全限定名。
构造函数
构造函数不能声明为const
构造函数初始化式只在构造函数的定义中而不是声明中指定。
构造函数分为两个阶段执行:1.初始化阶段 2.普通的计算阶段。
必须对任何const或引用类型成员以及没有默认构造函数的类类型的任何成员使用初始化式。
默认构造函数
一个类只要定义了一个构造函数,编译器就不会再自动生成默认构造函数了。
如果定义了其它构造函数,通常应定义一个默认构造函数。
隐式类类型转换
可以通过将构造函数声明为explicit,来防止在需要隐式转化的上下文中使用构造函数。
explicit关键字只能用于类内部的构造函数声明上。在类的定义体外部所做的定义上不再重复它。
通常,除非有明显的理由想要定义隐式转换,否则,单形参构造函数应该为explicit。当有转换需求时,用户可以显示地构造对象。
类成员的显示初始化
大多数对象可以通过运行适当的构造函数进行初始化,但是直接初始化简单的非抽象类的数据成员仍是可能的。对于没有定义构造函数并且其全体数据成员均为public的类,可以采用与初始化数组元素相同的方式初始化其成员。
我们知道pair的数据成员为public,然而下面这段代码却不能编译
pair<int, int> p = {0, 1};
因为pair的数据成员可以是抽象类,所以对于pair对象的初始化需要其构造函数进行初始化。