类经常被称为用户定义的类型(UDT)
一 类定义
1 类定义包括两部分:类头,由关键字class及其后面的类名构成。类体,由一对花括号包围起来。类定义后面必须接一个分号或一列声
明。例如:
class Screen { /* ... */ };
class Screen { /* ... */ } myScreen, yourScreen;
2 除了静态static 数据成员外数据成员不能在类体中被显式地初始化例如:
class First {
int memi = 0; // 错误
double memd = 0.0; // 错误
};
3 友元声明以关键字friend 开头它只能出现在类的声明中。由于友元不是授权友谊的类的成员所以它们不受其在类体中被声明的public、private 和protected 区的影响这里我们选择把所有友元声明组织起来放在类头之后。
友元也可以是一个完整的类
4
如果仅仅是声明但是没有定义类,那么我们就不能定义这类类型的对象。因为类类型的大小不知道,编译器不知道为这种类类型的对象预留多少存储空间。但是我们可以声明指向该类类型对象的引用或指针。但是,只有等完全定义完类后,才可以对引用或者指针进行赋值。
因为只有当一个类的类体已经完整时它才被视为已经被定义所以一个类不能有自身类型的数据成员但是当一个类的类头被看到时它就
被视为已经被声明了所以一个类可以用指向自身类型的指针或引用作为数据成员。
二 类对象
5 虽然每个类对象都有自己的类数据成员拷贝但是每个类成员函数的拷贝只有一份
例如:
Screen myScreen, groupScreen;
myScreen.home();
groupScreen.home();
当针对对象myScreen 调用函数home()时在home()中访问的成员_cursor 是对象myScreen 的数据成员当针对对象groupScreen 调用home()时数据成员_cursor 引用的是对象groupScreen 的数据成员但是两者调用的是同一个函数home() 同一个成员函数怎样能引用两个不同类对象的数据成员呢这种支持是通过this 指针实现的.
内联函数的定义:
在类体内定义的函数默认为inline
可以在类体的函数声明为inline,也可以在类体外的函数定义为inline,也可以两者皆有。
三 类成员函数
6 只有被声明为const 的成员函数才能被一个const 类对象调用关键字const 被放在成员函数的参数表和函数体之间对于在类体之外定义的const 成员函数我们必须在它的定义和声明中同时指定关键字const.
但是声明为const的成员函数也可以被非const类对象调用。
const成员函数可以被相同参数表的非const成员函数重载。
7 构造函数和析构函数是两个例外即使构造函数和析构函数不是const 成员函数,const类对象也可以调用它们。当构造函数执行结束、类对象已经被初始化时,类对象的常量性就被建立起来了析构函数一被调用常量性就消失所以一个const 类对象从构造完成时刻到析构开始时刻这段时间内被认为是const.
也可以将成员函数声明为volatile,如果一个类对象的值可能被修改的方式是编译器无法控制和检测的,则把它声明为volatile。对于一个volatile对象,只有volatile成员函数、构造函数和修改函数可以调用。
volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。
当要求使用volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。而且读取的数据立刻被保存。
8 13.36 mutable数据成员?
为了允许修改一个类的数据成员,即使它是一个const对象的数据成员,我们也可以把该数据成员声明为mutable(易变的)。mutable数据成员永远不会是const成员,即使它是一个const对象的数据成员。mutable成员总可以被更新,即使是在一个const成员函数中。
四 隐含的this指针
五 静态类成员的
static成员
1 同全局对象相比,静态成员的优势:
a 静态数据成员没有进入程序的全局名字空间,因此不存在与程序中其他全局名字冲突的可能性。
b 可以实现信息隐藏,静态成员可以使private成员,而全局对象不能
2 类的static成员必须在类体外初始化,const成员和引用成员必须在初始化列表进行初始化。
const static成员可以在类体内进行直接初始化。
a static成员在类体外初始化的时候不需要加static关键字
b 与全局对象一样,对于静态数据成员,在程序中只能提供一个定义。静态数据成员的初始化不应该放在头文件中,而应该放在含有
类的非inline函数定义的文件中。
c static const对象可以在类体内进行直接初始化,但是必须要在类体外定义,不需要加static修饰符
d 如果类成员函数的定义可以引用类的私有成员一样,静态数据成员的定义也可以。
e 在类的成员函数中我们可以直接访问该类的静态数据成员,而不必使用成员访问操作符。在类的static成员函数中只可以访问static数据成员。对这类函数的访问可以使用 类名::函数名 或者 对象名::函数名
f 静态数据成员的类型可以是其所属类,而非static数据成员只能被声明为该类对象的指针后引用。
class Bar
{
private:
static Bar mem1; //ok
Bar *mem2;//ok
Bar mem3;//error
}
g 静态数据成员可以被作为类成员函数的缺省实参而非static 成员不能.例如:
extern int var;
class Foo {
private:
int var;
static int stcvar;
public:
// 错误: 被解析为非 static 的 Foo::var
// 没有相关的类对象
int mem1( int = var );
// ok: 解析为 static 的 Foo::stcvar
// 无需相关的类对象
int mem2( int = stcvar );
// ok: int var 的全局实例
int mem3( int = ::var );
};
h 静态成员函数的声明除了在类体重的函数声明加上关键字static,以及不能声明为const或volatile之外,与非静态成员函数相同。出现在类体外的函数定义不能指定关键字static
静态成员函数没有this指针
i static类成员的指针被声明为普通指针
void (*psf)(double) = &Account::raiseInterest;
psf( 0.0025 );
1 在非静态类成员的指针和静态类成员的指针之间有一个区别。指向类成员的指针语法不能被用来引用类的静态成员。静态类成员是属于该类的全局对象和函数。它们的指针是普通
指针请记住静态成员函数没有this指针。
指向静态类成员的指针的声明看起来与非类成员的指针相同。解引用该指针不需要类对象。
七 联合
联合union是一种特殊的类。一个联合中的数据成员在内存中的存储是互相重叠的。
union TokenValue {
char _cval;
int _ival;
char *_sval;
double _dval;
};
如果在 TokenValue 的成员中最大的数据类型是_dval 则 TokenValue 的大小是 double 。
型对象的大小。缺省情况下 union 的成员都是公有成员 union 的名字可以被用在任何类名
可以被使用的地方。
union illegal_members {
Screen s; // 错误: 有构造函数
Screen *ps; // ok
static int is; // 错误: 静态成员
int &rfi; // 错误: 引用成员
};
八 位域:一种节省空间的成员
有一种被称为位域 bit-field 的特殊的类数据成员 它可以被声明用来存放特定数目的位。位域必须是有序数据类型,它可以有符号,也可以无符号,例如
class File {
// ...
unsigned int modified : 1; // 位域 (bit-field)
};
对于位域的访问方式与其他类数据成员相同 例如 类的私有位域只能在类的成员函数。和友元中被访问