一.对象数组与数组指针
1.1对象数组
对象数组是指每一个数组元素都是对象的数组。
定义一个一维数组的格式如下:
类名 数组名[下标表达式];
例:
A c[10]; //定义类A的对象数组c,含有10个对象数组元素
在建立数组时,有几个元素就调用几次数组元素。
在调用对象数组时,其一般形式为:
数组名[下标].成员名
在带一个参数的构造函数给对象数组赋值时,可以用大括号一次进行赋值。如:
A ob1[4]={11,22,33,44}; //类A的对象数组赋初值
如果构造函数有多个参数时,在定义数组时对其初始化的方式为:
A ob1[4]=A(1,2),A(3,4),A(5,6)}; //类A的对象数组ob1赋初值
同时,在定义数组时提供的参数不得超过数组元素的个数,如:
A ob1[4]={11,22,33,44,55}; //错误,实参格式超过对象数组的个数(构造函数只有一个参数)
1.2对象指针
对象指针就是用来存放对象地址的变量。声明对象指针的一般语法形式为:
类名 *对象指针名;
1.3this指针
this指针:自引用指针
每当创建一个对象,系统就把this指针初始化为指向该对象,即this指针的值是当前调用成员函数的对象的起始地址。
例如:
假设有一个对象a的成员函数disp,再调用成员函数a.disp时,编译系统就把对象a的起始地址赋给this指针,于是在成员函数引用数据成员时,就按照this指针的指向找到对象a的数据成员。例如disp函数要输出数据成员x的值,实际上是在执行:
cout<<"x="<<this->x<<endl;
由于当前this指针指向对象a,因此相当于执行:
cout<<"x="<<a.x<<endl;
这样就输出了对象a的数据成员x的值。
二.string类
使用string类必须在程序的开始包括头文件string,即要有如下语句:
#include<string>
string类的字符串对象也必须先定义后使用。定义格式如下:
string 对象1,对象2......;
例如:
string str1,str2; //定义string类对象str1和str2
三.向函数传递对象
3.1使用对象作为函数的参数
对象可以作为参数传递给函数。在向函数传递对象时,是通过“传值调用”传递给函数的,即单向传递,只由实参传递给形参,而不能由形参传回来给实参。因此函数中对对象的任何修改均不影响调用该函数的对象(实参)本身。
例如:
void sqr_it(Tr ob) //对象ob作为函数sqr_it的形参
3.2使用对象指针作为函数的参数
对象指针也可作为函数的参数。使用对象指针自我为函数的参数可以实现“传址调用”,即在函数调用时实参对象和形参对象指针变量指向同一内存地址。在函数调用的过程中,对形参对象指针所指对象值的改变也影响实参对象的值。
例如:
void sqr_it(Tr *ob) //对象指针作为函数的形参
3.3使用对象引用作为函数的参数
使用对象引用作为函数参数不但具有对象指针用作函数参数的优点,而且更简单直接。
例如:
void sqr_it(Tr &ob) //对象引用作为函数的形参
四.拷贝构造函数
拷贝构造函数是一种特殊的构造函数,其形参是本类对象的引用。其作用是在建立一个新对象时,使用一个已经存在的对象去初始化这个新对象。例如
Point p2(p1);
其作用是,在建立新对象p2时,用已经存在的对象p1去初始化新对象p2,在这个过程中就要调用拷贝构造函数。
4.1自定义拷贝构造函数
形式如下:
类名::类名(const 类名 &对象名)
{
//拷贝构造函数的函数体
}
例如:
class Point
{
public:
Point(int a,int b)
{
x=a;
y=b;
}
Point(const Point &p) //拷贝构造函数
{
x=2*p.x;
y=2*p.y;
}
private:
int x,y;
};
调用拷贝构造函数的一般形式为:
类名 对象2(对象1);
或者
类名 对象2=对象1;
4.2默认拷贝构造函数
每一个类都必须要有一个拷贝构造函数。如果程序员没有定义拷贝构造函数,系统就会自动生成一个默认拷贝构造函数。
4.3调用拷贝构造函数的三种情况
(1)当用类的一个对象去初始化该类的另一个对象时,拷贝构造函数将会被调用。如:
Point p2(p1); 或 Point p2=p1;
(2) 当函数的形参是类的对象,在调用函数进行形参和实参结合时,拷贝构造函数将会被调用。如:
void fun1(Point p)
{
p.print();
}
int main()
{
Point p1(10,20);
fun1(p1); //调用函数fun1时,实参p1是类Point的对象
return 0;
}
(3)当函数的返回值是类的对象,在函数调用完毕将返回值(对象)带回函数调用处时。此时就会调用拷贝构造函数,将此对象复制给一个临时的对象并传送到该函数的调用处。例如:
Point fun2() //函数返回值类型是Point类类型
{
Point p1(10,30);
return p1; //函数的返回值类型是Point类的对象
}
int main()
{
Point p2;
p2=fun2(); //函数调用完成,返回调用者时,调用拷贝构造函数
return 0;
}
五.静态成员
5.1静态数据成员
作用:实现同一个类多个数据成员之间的数据共享。
定义格式如下:、
static 数据类型 数据成员名;
如:
static int count;
static float sum;
注:
(1)静态数据成员的定义与普通数据成员类似,但在前面要加上static关键字。
(2)静态数据成员的初始化应该在类外单独进行,而且应在定义对象之前进行,一般在主函数main之前,类声明之后的特殊地带来为他提供定义和初始化.初始化格式如下:
数据类型 类名::静态数据成员名=初始值;
例如:
int Student::count=0;
float Student::sum=0.0;
注意:这时候不要在数据成员名前面加static。
(3)静态数据成员属于类,可以用"类名::"访问静态数据成员。
格式如下:
类名::静态数据成员名
如:
Student::count;
Student::sum;
(4)静态数据成员和静态变量一样,是在编译时创建并初始化。他在该类的任何对象被建立之前就存在。因此,静态数据成员可以在对象定义之前被访问。对象定义之后,公有的静态数据成员也可以通过对象进行访问。用对象进行访问静态数据成员的格式如下:
对象名.静态数据成员名;
对象名->静态数据成员名;
5.2静态成员函数
定义静态成员函数的格式如下:
static 返回类型 静态成员函数名(参数表);
调用静态成员函数的方法有:
类名::静态成员函数名(实参表)
对象.静态成员函数名(实参表)
对象指针->静态成员函数名(实参表)
一般情况下,静态数据成员只用来访问静态数据成员。私有静态成员函数不能做类外部的函数和对象访问。
使用静态成员函数,可以用它在建立任何对象之前调用静态成员函数,以处理静态数据成员,这是普通函数不能实现的功能。
如果在类外调用共有的静态成员函数,使用以下的格式较好:
类名::静态成员函数名()
静态成员函数和非静态成员函数的重要区别是:非静态成员函数有this指针,静态成员函数没有this指针。
静态数据成员一般不访问类中的非静态成员。如果需要访问的话,静态数据成员只能通过对象名(或对象指针,对象引用)来访问该对象的非静态成员。