十二、类
1. 类的定义和声明
类中的成员函数都默认为inline类型,所以即使在类定义体内的函数声明显示定义为inline类型,在进行函数定义时也能够将inline进行省略。
类声明: class Screen; 有时称为”向前声明“,一般用于编写相互依赖的类;
在C中定义一个struct的结构为:
struct 结构名
{
类型 变量名;
类型 变量名;
...
} 结构变量;
因此拓展为C++后,保留了这一特性, 也需要在class后加上一个“;”
struct 结构名
{
类型 变量名;
类型 变量名;
...
} 结构变量;
等价于
struct 结构名
{
类型 变量名;
类型 变量名;
...
} ;
struct 结构名 结构变量; class 也可以写成这样的形式;
2. 隐含的this指针
一般来说没必要在类中使用this指针,但是对于一些类的成员函数来说需要返回对调用该函数的对象的引用,比如一个方法:
screen.move(4, 0).set("#"),move方法中就应该返回"*this"
对于const成员函数,不能从中返回指向类对象的普通引用。只能返回*this作为一个const引用: const Screen& dispaly() const{return *this};
对于类成员函数来说:
const Screen& dispaly( ) const{return *this};
Screen& dispaly( ){return *this}; 是可以算成重载函数的,因为第一个函数相当于传入了一个指向const类型的this指针。
如果真的想在const成员函数中改变某值,则需要将变量声明为mutable类型的。
3. 类作用域
类中一般的成员使用成员访问操作符来访问,另一些直接通过类使用作用域操作符(::)来访问。
定义类型的成员,比如在类中包含 typedef int index, 使用作用域操作符来访问: Screen::index
全局作用域操作符: 在": :" 前不出现任何类名。
4. 构造函数
初始化列表: Sales_item::Sales_item() : isbn(book), units_sold(0), revenue(0.0) {}
这种初始化方式比起在{}中赋值要减少一个赋值步骤,因为进入到函数体之前,都必须对类成员进行初始化
有些类类型成员必须在初始化列表中进行初始化:1、没有默认构造函数的类类型成员;2、const成员;3、引用类型成员
初始化成员列表中的顺序应该尽量与变量的声明顺序一致,尤其是当要使用一个变量来初始化另一个变量的时候;
一旦类定义了构造函数,编译器就不会自动生成默认构造函数,需要自己定义;
默认构造函数使用:
A a(); // 错误! 将被理解为函数的声明
A a; // 正确!
A a = A(); // 正确!
隐式类类型转换:
可以用单个实参来掉用的构造函数定义了从形参类型到该类类型的一个隐式转换:
A a(string str){} 在一个void fun(A a){} 函数中可以使用string类型的形参
为防止隐式转换,可以在构造函数前加explicit。
通常,除非有明显的理由想要定义为隐式转换,否则,单形参构造函数应该为explicit。
对于没有定义构造函数,且全体数据成员均为public的类,可以使用类似于 A a = {1, 2}方式初始化
对于pair<int, int> p = {0, 42}是错误的,因为pair有自己的构造函数
5. 友元
允许特定的非成员函数访问一个类的私有成员,同时仍然阻止一般的访问。
友元机制允许一个类将对其非公有成员的访问权授予指定的函数或类;
Class A
{
friend class B;
private:
int a;
}
void B::b(A aa)
{
int bb = aa.a;
}
一个类必须把它希望与之建立友元关系的重载函数集中的每个函数都声明为友元
extern
ostream& storeOn( ostream &, Screen & );
extern
BitMap& storeOn( BitMap &, Screen & );
// ...
class
Screen
{
friend
ostream& storeOn( ostream &, Screen & );
friend
BitMap& storeOn( BitMap &, Screen & );
// ...
};
需要注意友元声明与友元定义之间的关系!
class
Window;
class
Screen
{
friend
class
Window;
// ...
};
6. static类成员
当在类的外部定义static成员函数时,不需要重复指定static保留字,只出现在类定义体内部的声明处;
static成员是类的组成部分,但不是任何对象的组成部分;因此,static成员函数没有this指针。同时不能被声明为const,因为将成员函数声明为const就是承诺不会修改该函数所属的对象。
static数据成员必须在类定义体的外部定义。而不是通过构造函数初始化,一般在类成员实现文件中初始化;
类的static成员,以及普通数据成员,不能在类的定义体中初始化!除了常量const,但是该数据成员仍必须在类的定义体之外进行定义!
const static 与 static const没有差别!
static数据成员的类型可以是该成员所属的类类型。非static成员被限定声明为其自身类对象的指针或引用;
class A
{
private:
static A a1; // OK
A * a2; // OK
A a3; // Wrong
}