类的其他特性
-
构造函数初始值列表
①.定义
构造函数除了有名字,参数列表和函数体之外,还可以有初始化列表,初始化列表以冒号开头,后跟一系列以逗号分隔的初始化字段;如果没有在构造函数的初值列表中显示的初始化成员,则该成员将在构造函数体执行之前执行默认初始化。
class example { public: example(int x,int y):a(x) ,b(y)//初始化值列表 { }; private: int a; int b; };//定义了一个名为 example的 类
②.初始化和赋值
构造函数的执行可以分成两个阶段:初始化阶段、计算阶段,初始化阶段先于计算阶段;计算阶段即是执行构造函数体的内容,给已经初始化的对象赋值。
class example { public: example(int x,int y) { a = x;//赋值 b = y;//赋值 }; private: int a; int b; };//定义了一个名为 example的 类
③.应用
使用初始值列表进行成员初始化可以提高效率:如果不用初始值列表,那么类对自己的类成员分别进行的是一次隐式的默认构造函数的调用,和一次赋值操作符的调用;
const 成员变量、引用成员变量必须使用初始值列表初始化:因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的;
没有默认构造函数的类成员必须使用初始值列表初始化。
-
友元
①.概念
友元允许一个类将对其非公有成员的访问权授予指定的函数或者类,友元的声明以 friend 开始。
②.友元函数
友元函数是指某些虽然不是类成员函数却能够访问类的所有成员的函数,类授予它的友元特别的访问权。友元声明只能出现在类定义的内部,友元不是类的成员,不受访问控制权限的约束,一般在类的开始或者结束集中声明友元。
class example { friend int addAB( example &exp); //友元 public: example(int x,int y):a(x) ,b(y)//初始化值列表 { }; private: int a; int b; };//定义了一个名为 example的 类 int addAB( example exp); //函数声明
友元的声明仅仅指定了访问权限,还需要在友元声明之外再专门对函数进行一次声明,通常把友元的声明与类本身放置在同一个头文件中。
③.友元类
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类,声明友元即为另一个类开放权限。
④.友元成员函数
可以指定仅允许类的某个成员函数对本类有完全的访问权限,要想另某个成员函数作为友元时,必须指定该成员属于哪个类。
class A;
class B
{
public:
void showAdata( A &a); //A 的友元函数,A 中为该函数开放权限
};
class A
{
public:
A( int x) :data(x) {};
friend void B::showAdata( A &a); //该函数是友元成员函数的声明,不能定义
private:
int data;
};
void B::showAdata( A &a) //只有在定义类A后才能定义该函数
{
cout << a.tata << endl;
}
当用到友元成员函数时,需注意友元声明和友元定义之间的相互依赖,必须先定义包含成员函数的类,才能将成员函数设为友元。
-
隐式的类类型转换
①.概念
如果构造函数只接受一个实参,则该构造函数实际上定义了一条从构造函数的参数类型向类类型隐式转换的规则。
class example { public: example(int x):a(x) // 只有一个参数,为转换构造函数,int 转换成 example { }; private: int a; int b; };//定义了一个名为 example的 类
②.类型转换
class example { public: example(int x):a(x) // 只有一个参数,为转换构造函数,int 转换成 example { }; private: int a; int b; };//定义了一个名为 example的 类 example exp = 10;//隐式转换, 等同与 example temp(10);example exp = temp;
③.抑制隐式转换
使用 explicit 关键字来防止类构造函数的隐式自动转换。
class example { public: explicit example(int x):a(x) // 阻止隐式转换 { }; private: int a; int b; };//定义了一个名为 example的 类 example exp = 10;//错误,必须显示的转换 example exp(10);
类的特殊成员
①.类的静态成员变量
在成员声明之前加关键字 static 可以使其和类关联在一起,静态成员在这个类的所有的对象之间是共享的,只有一个副本。静态成员变量类的内部只是声明,定义及初始化必须在类外,并且静态成员变量定义在任何函数之外。
class A
{
public:
static int aCount;//声明静态成员
A( int x ):a(x){};
private:
int a;
};
int A::aCount = 1;//类外定义静态成员
int main()
{
// int A::aCount = 1; 错误,必须定义在任何函数之外
A a(10);
cout << a.aCount << endl;//访问静态成员
return 0;
}
②.类的静态成员函数
静态成员函数也不和任何对象绑定在一起,也不包含 this 指针;static 成员不属于对象,所以不能将 static 函数声明为 const ;静态成员函数只能访问静态成员数据,其他静态成员函数和类之外的函数。
③.类的 const 成员变量
const 成员变量不能在类的内部初始化,在类的内部只是声明,只能通过构造函数的初始化列表进行初始化,并且必须进行初始化。
class A
{
public:
A( int x ,int y):a(x),aCount(y){};// const 成员必须使用初始化列表进行初始化
private:
int a;
const int aCount;//声明 const 成员,不能类内初始化
};
④.类的 const 成员函数
类的成员函数后面加 const,表明这个函数不会对这个类对象的数据成员作任何改变;只有被声明为const的成员函数才能被一个 const 类对象调用。
class A
{
public:
A( int x ,int y):a(x),aCount(y){};// const 成员必须使用初始化列表进行初始化
int getaData()
{
return a;
};
int getaData() const // 类外定义时也必须加 const
{
return a;
};
private:
int a;
const int aCount;//声明 const 成员,不能类内初始化
};
A a;
a.getaData();//调用非 const 版本
const A aa;
aa.getaData();//调用 const 版本
⑤.可变数据成员
用关键字 mutable 修饰成员,表示该数据成员是可变的,即使是在 const 成员函数中也可以被改变
class A
{
public:
A( int x ,int y):a(x),aCount(y){};// const 成员必须使用初始化列表进行初始化
void seetaData( int i) const
{
a = i;//在 const 成员函数中也可以被改变
};
int getaData() const // 类外定义时也必须加 const
{
return a;
};
private:
mutable int a;// 可变数据成员
const int aCount;//声明 const 成员,不能类内初始化
};