◆定义类时应注意的事项
①
在类体内允许对成员函数进行定义,但是不允许对数据成员赋值。例如,下述的定义时错误的:
class Tpoint
{
.........
private:
int X(5),Y(6); //错误
};
这里不允许对数据成员X和Y进行初始化。
②
类中成员的类型是指数据类型。类中任何成员不能使用auto,extern和register存储类说明符进行修饰。
(其他略)
◆静态数据成员
静态数据成员定义在类体内,定义时前边加关键字static。
静态数据成员定义后,必须再对它进行初始化。静态数据成员被定义在类体内,但是对它的初始化在类体外进行。
具有一下特点:
1、定义在类体内,初始化在类体外。初始化后才可使用。
2、静态数据成员是属于类的,而不是属于某个对象的。静态数据成员是所有对象共享的,使用它可以节省内存。因此,引用静态数据成员时可以使用类名,其格式如下所示:
<类名>::<静态数据成员名>
3、定义静态数据成员像定义一般数据成员一样,应该给出数据类型和访问权限。
4、静态数据成员的寿命是长的,被存放在内存的静态工作区。
◆静态成员函数
静态成员函数可定义在类体内,也可定义在类体外,定义在类体外时按成员函数的定义格式,但不必加static关键字。
静态成员函数的实现可以直接引用静态数据成员,但不能直接一哟你非静态数据成员。如果引用非静态成员时,则可通过对象来引用。
使用类名和作用域运算符引用静态成员函数的格式如下:
<类名>::<静态成员函数名>(<参数表>)
使用对象引用静态成员函数的格式如下:
<对象名>. <静态成员函数名>(<参数表>)
特点:
1、由于静态成员函数是用于处理类的,因此不能使用this指针。
2、由于静态成员函数的程序代码在编译阶段就被分配内存空间了,因此不能被定义为虚函数。
例如:
1
#include<iostream>
2
using namespace std;
3
class M
4
{
5
public:
6
M(int a)
7
{
8
A=a;
9
B+=a;
10
}
11
static void fun(M m);
12
private:
13
int A;
14
static int B;
15
};
16
17
void M::fun(M m)
18
{
19
cout<<"A="<<m.A<<endl;
20
cout<<"B="<<B<<endl;
21
}
22
int M::B=1;
23
int main()
24
{
25
M P(8),Q(18);
26
M::fun(P);
27
Q.fun(Q);
28
}
29
显示结果为:
A=8
B=27
A=18
B=27
在主函数中,出现了两种调用静态成员函数的格式,前一种使用类名和作用域运算符后一种使用的是对象名。即M::fun(P);
和Q.fun(Q);
两种方式都可以。
◆指向类的成员函数的指针
读程序:
1
#include<iostream>
2
using namespace std;
3
class A
4
{
5
public:
6
A(int i)
7
{a=i;}
8
int fun(int b)
9
{return a*c+b;}
10
int c;
11
private:
12
int a;
13
};
14
15
int main()
16
{
17
A x(18);
18
int A::*pc;
19
pc=&A::c;
20
x.*pc=5;
21
int(A::*pfun)(int);
22
pfun=&A::fun;
23
A *p=&x;
24
cout<<(p->*pfun)(10)<<endl;
25
return 0;
26
}
27
运行结果为100
◆友元类
友元类是一种友元,它把一个类作为另一个类的友元。
特点:
例如,Y类是X类的友元类,则Y类中的成员函数可以访问X类中的所有成员,包含私有成员和保护成员。否则一个类的成员函数是不可访问另一个类中的私有成员和保护成员的。另外,友元类的关系是不可逆的。
1
#include<iostream>
2
using namespace std;
3
class X
4
{
5
friend class Y;
6
public:
7
void Set(int i)
8
{
9
x=i;
10
}
11
void Display()
12
{
13
cout<<"x="<<x<<","<<"y="<<y<<endl;
14
}
15
private:
16
int x;
17
static int y;
18
};
19
class Y
20
{
21
public:
22
Y(int i,int j);
23
void Display();
24
private:
25
X a;
26
};
27
28
int X::y=10;
29
Y::Y(int i,int j)
30
{
31
a.x=i;
32
X::y=j;
33
}
34
void Y::Display()
35
{
36
cout<<"x="<<a.x<<","<<"y="<<X::y<<endl;
37
}
38
int main()
39
{
40
X b;
41
b.Set(15);
42
b.Display();
43
Y c(16,19);
44
c.Display();
45
b.Display();
46
return 0;
47
}
48
运行结果:
X=15 Y=10
X=16 Y=19
X=15 Y=19
◆引用作函数返回值
1
#include<iostream>
2
using namespace std;
3
class N
4
{
5
public:
6
N(int i,int j)
7
{
8
x=i;
9
y=j;
10
}
11
void Print()
12
{
13
cout<<x<<","<<y<<endl;
14
}
15
int Getxy()
16
{
17
return x+y;
18
}
19
private:
20
int x,y;
21
};
22
23
N &fun()
24
{
25
static N a(23,45);
26
return a;
27
}//返回值的类型为N ,所以在主函数可以被p赋值。
28
int main()
29
{
30
N p(18,25);
31
p.Print();
32
cout<<fun().Getxy()<<endl;
33
fun()=p;
34
cout<<fun().Getxy()<<endl;
35
return 0;
36
}
运行结果为:
18,25
68
43
◆运算符new和运算符delete
使用运算符new创建变量
格式:new <类型> (<初始值表>)
其中,<初始值表>也可以省略。该运算符的表达式是一个地址值,通常将它赋值给一个相同类型的指针。如果<初始值表>被省略,则表示只创建一个指向某种<类型>的指针,只在内存中分配一个可放下指定<类型>数据的空间;否则同时给所指向的变量进行初始化。例如: int *p;
p=new int(8);
这里,p是一个指向int 型变量的指针,并且对所指向的int 型变量进行初始化。
通常,使用new运算符创建一个变量,如果成功,其表达式为一个非0的地址值,将它赋给一个指针,让该指针指向这个变量,否则表达式值为0,表明创建失败。
使用new运算符创建数组
格式: new <类型> [<大小>]
例如: int *pa;
pa=new int [5];
这里,pa是一个指向具有5个int 型的一维数组的指针。该数组的值可以通过下述赋值:
pa[0]=1; pa[1]=2; pa[2]=3 ; pa[3]=4; pa[4]= 5;
使用运算符delete释放变量和数组
格式:delete <指针名>
使用delete运算符释放数组的格式:
delete [] <指针名>
1
#include<iostream>
2
#include<cstdlib>
3
using namespace std;
4
int main()
5
{
6
int *p,*pa;
7
p=new int(10);
8
pa=new int[10];
9
if(!pa)
10
{
11
cout<<"Error!"<<endl;
12
exit(1);
13
}
14
int i;
15
for(i=0;i<10;i++)
16
pa[i]=i+10;
17
for(i=0;i<10;i++)
18
cout<<pa[i]+*p<<" ";
19
cout<<endl;
20
delete p;
21
delete pa;
22
return 0;
23
}
24
运行结果为:
20 21 22 23 24 25 26 27 28 29
◆全局对象与静态对象
读程序:
1
#include<iostream>
2
#include<cstring>
3
using namespace std;
4
class A
5
{
6
public:
7
A(char *str);
8
~A();
9
private:
10
char string[80];
11
};
12
13
A A0("Test 1");
14
A::A(char *str)
15
{
16
strcpy(string,str);
17
cout<<"Constructor called of "<<string<<".\n";
18
}
19
A::~A()
20
{
21
cout<<"Destructor called of "<<string<<".\n";
22
}
23
void fun()
24
{
25
A A1("FunObject");
26
A A6("Test 2");
27
static A A2("Internal-StaticObject");
28
cout<<"In fun().\n";
29
}
30
A A7("Test 3");
31
A A3("GolbalObject");
32
static A A4("External-StaticObject");
33
int main()
34
{
35
A A5("MainObject");
36
cout<<"In main(),before calling fun().\n";
37
fun();
38
cout<<"In main(),after calling fun().\n";
39
return 0;
40
}
41
运行结果为:
Constructor called of Test 1.
Constructor called of Test 3.
Constructor called of GolbalObject.
Constructor called of External-StaticObject.
Constructor called of MainObject.
In main(),before calling fun().
Constructor called of FunObject.
Constructor called of Test 2.
Constructor called of External-StaticObject.
In fun().
In main(),after calling fun().
Destructor called of Test 2.
Destructor called FunObject.
In main(),after calling fun().
Destructor called of MainObject.
Destructor called of Internal-StaticObject.
Destructor called of External-StaticObject.
Destructor called of GolbalObject.
Destructor called of Test 3.
Destructor called of Test 1.
仔细观察外部函数和主函数对象的先后顺序:
先从全局对象开始然后主函数,然后再被调用函数的对象,即外部函数的对象。注意是一调用完外部函数,立即释放外部函数的对象,然后才继续主函数的释放。
◆从const成员函数返回*this
在普通的非const成员函数中,this的类型是一个指向类类型的const指针。可以改变this所指向的值,但不能改变this所保存的地址。在const成员函数中,this的类型是一个指向
const类类型对象的const指针。既不能改变this所指向的对象,也不能改变this所保存的地址。
不能从const成员函数返回指向类对象的普通引用。const成员函数只能返回*this作为一个const引用。
◆基于const的重载
const对象只能使用const成员。非const对象可以使用任一成员,但非const版本是一个更好的匹配。