第五章 特殊函数和成员
**大家想一起学习交流的可以加群,QQ:755422568。**
一、对象成员的初始化
一个类中说明具有某个类的类型的数据成员,这些成员称为对象成员。
对象成员的构造函数调用顺序取决于这些对象成员在类中的说明顺序,跟它们在成员初始化列表中给出的顺序无关。如下示例:
#include <iostream>
using namespace std;
class object{
private:
int val;
public:
object():val(0){
cout << "Default constructor for object" << endl;
}
object(int i):val(i){
cout << "Constructor for object" << val << endl;
}
~object(){
cout << "Destructor for object" << val << endl;
}
};
class container{
private:
object one; //初始化顺序与对象成员产生的顺序有关,排在前面的先初始化
object two;
int data;
public:
container():data(0){
cout << "Default constructor for container" << endl;
}
container(int i,int j,int k);
~container(){
cout << "Destructor for container" << data << endl;
}
};
container :: container(int i,int j,int k) : two(i),one(j){ //与初始化列表顺序无关
data = k;
cout << "Constructor for container" << data << endl;
}
void main(){
container obj,anObj(5,6,10);
}
//为对象成员one调用无参构造函数
Default constructor for object
//为对象成员two调用无参构造函数
Default constructor for object
//为对象obj调用container类的无参构造函数
Default constructor for container
//为对象成员one调用构造函数
Constructor for object 6
//为对象成员two调用构造函数
Constructor for object 5
//为对象anObj调用container类的有参构造函数
Constructor for container 10
//调用container类的析构函数对象anObj
Destructor constructor for container 10
//析构数据成员为5的对象two
Destructor for object 5
//析构数据成员为6的对象one
Destructor for object 6
//调用container类的析构函数对象obj
Destructor for container 0
//析构函数对象two
Destructor for object 0
//析构函数对象one
Destructor for object 0
二、静态成员
(1)、静态成员
如果类的数据成员或成员函数使用关键字static进行修饰,这样的成员称为静态数据成员或静态成员函数,统称为静态成员。
class Test{
static int x; //静态数据成员
int n;
public:
Test(){}
Test(int a,int b){
x = a;
n = b;
}
static int func(){ //静态成员函数
return x;
};
static void sfunc(Test&r,int a ){ //静态成员函数
r.n = a;
};
int Getn(){ //非静态成员函数
return n;
}
};
int Test :: x = 25;
#include <iostream>
using namespace std;
void main(){
cout << Test :: func(); //x在产生对象之前即存在,输出25
Test b,c;
b.sfunc(b,58);
cout << " " <<b.Getn();
cout << " " <<b.func();
cout << " " <<c.func();
Test a(24,56);
cout << " " << a.func() << " " << b.func() << " " << c.func() << endl;
/**
*输出结果如下:
*25 58 25 25 24 24 24
*/
}
1、静态数据成员只能说明一次,在类中没有对静态数据成员进行声明,则必须在文件作用域内进行定义,初始化必须进行成员名限定。
2、在类中定义的静态成员函数是内联的。
3、静态成员与一般成员有以下不同:
① 可以不指向某个具体的类,只与类名连用;
② 在没有建立对象之前,静态成员就已经存在;
③ 静态成员是类的成员,不是对象的成员;
④ 静态成员为该类的所有对象共享,被存于公共内存中(类的任何成员函数都可以访问静态成员);
⑤ 静态成员没有this指针,所以除非显式的把指针传给它们,否则不能存取类的数据成员;
⑥ 静态成员函数不能被说明为虚函数;
⑦ 静态成员函数不能直接访问非静态成员,只能通过对象名(或指向对象的指针)来访问。
(2)、静态对象
#include <iostream>
using namespace std;
class test{
private:
int n;
public:
test(int i){
n = i;
cout << "constructor:" << i << endl;
}
~test(){
cout << "destructor:" << n << endl;
}
int getn(){
return n;
}
void inc(){
++n;
}
};
void main(){
cout << "loop start" << endl;
for(int i = 0;i < 3;ji++){
static test a(2); //静态对象
test b(2); //普通对象
a.inc();
b.inc();
cout << "a.n" << a.getn() << endl;
cout << "b.n" << b.getn() << endl;
cout << "loop endl" << endl;
cout << "Exit main()" << endl;
}
}
输出结果如下:
loop start
constructor;2
constructor;2
a.n = 4
b.n = 4
destructor:4
constructor;2
a.n = 5
b.n = 4
destructor:4
loop endl
Exit main()
destructor:5
1)、构造函数在代码执行过程中,第一次遇到它的变量定义时被调用,但直到整个程序结束之前仅调用一次。
2)、析构函数在整个程序退出之前被调用,也只调用一次。
三、友元函数
友元函数可以存取私有成员、公有成员和保护成员。
友元函数可以是一个类或函数,尚未定义的类也可以作为友元引用
(1)、类本身的友元函数
class Point{
private:
double X,Y;
public:
Point(double xi,double yi){
X = xi;
Y = yi;
}
double GetX(){
return X;
}
double GetY(){
return Y;
}
friend double distances(Point&,Point&); //声明友元函数
};
double distances(Point& a,Point& b){ //像普通函数定义友元函数
double dx = a.X - b.X;
double dx = a.Y - b.Y;
return sqrt(dx*dx+dy*dy)
}
主要目的:提高程序效率
主要优点:不必考虑类的各种使用情况
主要问题:友元函数可以直接访问对象的私有成员,可以省去调用类成员函数的开销,但会破坏了封装和数据隐藏,导致程序的可维护性变差。
友元函数可以在类中声明时定义,如果在类外定义,不能使用friend关键字。
(2)、将成员函数用友元
class Two; //先声明Two类,以便One类可以引用Two类
class One {
private:
int x;
public:
One(int a) {
x = a;
}
int getX() {
return x;
}
void func(Two&);
};
class Two {
private:
int y;
public:
Two(int a){
y = a;
}
int getY(){
return y;
}
friend void One :: func(Two&); //声明One类的func函数为友元函数
};
//定义友元函数
void One::func(Two &t){
t.y = x;
}
void main(){
One obj1(5);
Two obj2(8);
cout << obj1.Getx() << " " << obj2.Gety() << endl;
obj1.func(obj2);
cout << obj1.Getx() << " " << obj2.Gety() << endl;
/**
*输出结果如下:
* 5 8
* 5 5
*/
}
(3)、将一个类说明为另一个类的友元
友元关系不具有交换性
四、const对象
一个const对象只能访问const成员函数。
(1)、常量成员
常量成员包括常量数据成员、静态常数据成员和常引用。
const int a; //常数据成员只能通过初始列表来获得初值
static const int b; //静态常数据成员
const int& r; //常引用只能通过初始化列表来获得初值
const int Base :: b = 125; //静态常数据成员在类外初始化
Base :: Base(int i,int j) :x(),a(),r(){} //初始化列表
(2)、常引用作为函数参数
void Display(const double& r);
(3)、常对象
Base const a(25,68); //常对象必须初始化
(4)、常成员函数
五、数组和类
class Test{
int num;
double f1;
public:
Test(int n){
num = n;
}
Test(int n,double f){
num = n;
f1 = f;
}
int GetNum(){
return num;
}
};
//使用类对象数组和指针
void main(){
Test one[2] = [2,4],* p;
Test two[2] = {Test(1,2,3),Test(5,9.5)};
for(int i = 0;i < 2;i++){
cout << "two[" << i << "] = (" << p->GetNum() << "," << p-> GetF() << ")" << endl;
}
}
//使用对象指针数组
void main(){
Test * one[2] = { new Test(2), new Test(4)};
Test * two[2] = {Test(1,2,3),Test(5,9.5)};
for(int i = 0;i < 2;i++){
cout << "one[" << i << "] = (" << one[i]->GetNum() << endl;
}
for(int i = 0;i < 2;i++){
cout << "two[" << i << "] = (" << two[i]->GetNum() << "," << two[i]-> GetF() << ")" << endl;
}
}
六、指向类成员函数的指针
int(A :: * pfun)(int); //声明指向类A的成员函数的指针
pfun = A :: value; //指针指向具体成员函数value