参考资料:《21天学通C++》
对象
对象概述
对象是现实世界中的实体,其一般具有以下特征:
- 每个对象都有一个用于与其他对象相区别的名字。
- 具有某些特征,称为属性或状态。
- 有一组操作,每一个操作决定对象的一种行为,即对象能干什么。
- 对象的状态只能被自身行为所改变。
- 对象之间以消息传递的方式相互通信。
注意:上述特征在面向对象程序设计中分别被抽象为对象名、属性、事件、方法和消息。这是面向对象程序设计的基础。
对象数组
对象数组是指以数组元素为对象的数组,该数组中若干个元素必须是同一个类的若干对象。对象数组的定义、赋值和引用与普通数组一样,只是数组的元素与普通数组不同,它是同类的若干个对象。
一般来说,定义对象数组的格式如下:
类名 数组名[大小]
其中参数说明如下:
- 类名:指出该数组元素是属于该类的对象。
- 数组名:定义该对象数组的名称,它必须是C++的标识符。
- 大小:方括号内的数字给出某一维的元素个数。一维对象数组只有一个方括号,二维对象数组要有两个方括号等。
例如,下列语句定义了一个一维对象数组:
Cbook dates[7];
上述语句表明dates是一维对象数组名,该数组有7个元素,其中的对象属于Cbook类,也即每个元素都是类Cbook的对象。
与普通数组类似,对象数组可以被赋初值,也可以被赋值。
例1 对象数组的定义和赋值
#include <iostream>
using namespace std;
class DATE { //声明类
public: //公有成员
DATE(int m, int d, int y);
void print();
private: //私有成员
int month, day, year;
};
DATE dates[4] = {DATE(7, 7, 2001), DATE(7, 8, 2001), DATE(7, 9, 2001), DATE(7, 10, 2001)}; //初始化
DATE :: DATE(int m, int d, int y) { //定义成员函数(构造函数)
month = m;
day = d;
year = y;
}
void DATE :: print() { //定义成员函数
cout << month << "\t" << day << "\t" << year << endl;
}
void main() {
int i;
for(i = 0; i < 4; i++)
dates[i].print(); //调用对象的print函数
}
输出:
7 7 2001
7 8 2001
7 9 2001
7 10 2001
构造函数
构造函数的概念
注意:在类中定义成员变量时,不能给这些变量赋初值。
构造函数是在类中定义的一种特殊的函数,其函数名称与类的名称相同。
构造函数的主要功能是为对象分配空间,也可以用来为类成员变量赋初值,因此构造函数没有返回类型,也没有return语句。
构造函数具有以下性质:
- 构造函数的名字必须与类的名字相同
- 构造函数的参数可以是任何数据类型,但它没有返回值,不能为它定义返回类型。
- 对象定义时,编译系统自动调用构造函数完成对象内存空间的分配和初始化工作。
- 构造函数是类的成员函数,具有一般成员函数的所有性质,可以访问类的所有成员,可以是内联函数,可以带参数表,可以有默认的形参值,也可以重载。
构造函数的声明和定义
构造函数的声明和定义与普通成员函数的声明和定义类似。
例如,下面的语句给出了一个类的声明和定义,其中包含了构造函数的声明和定义:
class complex {
private:
double real, imag; //定义复数的实部和虚部
public:
complex(double r, double i) { //声明构造函数,其名字与类名相同
real = r;
imag = I; //初始化私有数据成员imag和real
}
void disp() {
cout << real << "+" << imag << "i" << endl;
}
};
上面的语句定义了一个类complex,其包含两个私有成员变量,在公有成员中,其包含了两个成员函数:complex()函数和disp()函数。其中,complex函数为构造函数,其函数名与类名相同,并且带有两个参数。
此外,构造函数可以在类中声明,在外部定义。
例如,上述上明定义的类可以改写成以下形式:
class complex {
private:
double real, imag; //定义复数的实部和虚部
public:
complex(double r, double i); //声明构造函数
void disp() {
cout << real << "+" << imag << "i" << endl;
}
};
complex :: complex(double r, double i) { //定义构造函数
real = r;
imag = I;
}
注意:在类的外部定义构造函数时,需要在函数前增加类名和域运算符。
一般都需要给类定义构造函数,如果没有定义,编译系统就会自动生成一个默认的构造函数,这个默认的构造函数不带任何参数,只能给对象开辟一个存储空间,不能为对象赋初值。
构造函数的调用
在定义了构造函数之后就可以对其进行调用了。一般来说,在定义对象的同时会自动调用构造函数,不需要显式调用。构造函数的调用格式为:
类名 对象名(实参表)
例7 构造函数的调用
#include <iostream>
using namespace std;
class complex {
private:
double real, imag; //定义复数的实部和虚部
public:
complex(double r, double i); //声明构造函数
void disp() { //声明成员函数
cout << real << "+" << imag << "i" << endl;
}
};
complex :: complex(double r, double i) { //定义构造函数
real = r; //成员变量初始化
imag = i;
}
int main(void) {
complex op1(1.5, 3.0); //创建对象
op1.disp();
return 0; //调用类的成员函数
}
输出:
1.5+3i
上述代码中,首先定义了类complex及其构造函数,在类外定义了该构造函数。在main()函数中,没有直接调用构造函数,而是在声明了对象op1的同时系统自动调用了该构造函数。
不带参数的构造函数
构造函数也可以不带参数。
例8 不带参数的构造函数
#include <iostream>
using namespace std;
class myclass { //定义类
private: //定义私有成员
int a;
public:
myclass(); //声明不带参数的构造函数
void disp() {
cout << "a * a = " << a << endl;
}
};
myclass :: myclass() { //定义构造函数
cout << "initialized.\n";
a = 10; //给变量初始化
}
int main(void) {
myclass s; //创建对象,执行构造函数
s.disp(); //调用成员函数
return 0;
}
输出:
initialized.
a * a = 10
上述代码中,定义了一个类myclass,在类中声明了该类的构造函数myclass()。该构造函数无参数,在类外定义该构造函数,输出提示信息“initialized”并给私有变量赋初值0。
注意:不带参数的构造函数的初始化是固定的,如果希望在建立对象时通过参数初始化数据成员,应使用带参数的构造函数。
带有默认参数的构造函数
在实际应用中,有些构造函数的参数值通常是不变的,只有在特殊情况下才改变它的值,这时可以将构造函数定义成带默认参数的值的构造函数。此时在定义对象时可以不指定实参,用默认参数值来初始化数据成员。
例9 带默认参数的构造函数
#include <iostream>
#include <math.h>
using namespace std;
class complex {
private:
double real, imag;
public:
complex(double real = 0.0, double imag = 0.0); //声明带有默认参数的构造函数
double abscomplex();
};
complex :: complex(double r, double i) { //定义构造函数
real = r; //成员初始化
imag = i;
}
double complex :: abscomplex() { //定义成员函数
double n;
n = real * real + imag * imag;
return sqrt(n); //返回平方根值
}
int main(void) {
complex ob1; //创建对象ob1
complex ob2(1.1); //创建对象ob2
complex ob3(1.1, 2.2); //创建对象ob3
cout << "abs of complex ob1 = " << ob1.abscomplex() << endl;
cout << "abs of complex ob2 = " << ob2.abscomplex() << endl;
cout << "abs of complex ob3 = " << ob3.abscomplex() << endl;
return 0;
}
输出:
abs of complex ob1 = 0
abs of complex ob2 = 1.1
abs of complex ob3 = 2.45967
上述代码中,对象ob1在定义时没有传递任何参数,所以real和imag均去构造函数的默认值初始化,real和imag均为0.0。对象ob2在定义时传递了一个参数,按顺序传递给了第一个形参real,第二个形参imag取默认值,所以real为1.1,imag为0.0。对象ob3在定义时传递了两个参数,所以real为1.1,imag为2.2。
注意:创建对象调用的构造函数是否带参数,其创建的对象对成员变量的初始化程度是不一样的。
构造函数的重载
C++允许对构造函数的重载,即可以定义多个参数及参数类型不同的构造函数,用多种方法对对象初始化。
例10 构造函数的重载
#include <iostream>
using namespace std;
class point {
private:
double fx, fy;
public:
point(); //声明不带参数的构造函数
point(double x, double y); //声明带两个参数的构造函数
void showpoint();
};
point :: point() { //定义不带参数的构造函数
fx = 0.0; //成员初始化
fy = 0.0;
}
point :: point(double x, double y = 5.5) { //定义带两个参数的构造函数
fx = x; //成员初始化
fy = y;
}
void point :: showpoint() { //定义成员函数
cout << fx << "\t" << fy << endl;
}
int main(void) {
point p1; //用构造函数point创建对象
cout << "The fx and fy of p1: ";
p1.showpoint();
point p2(1.0); //用构造函数point(double x, double y = 5.5)创建对象
cout << "The fx and fy of p2: "; //fy用默认值5.5初始化
p2.showpoint();
point p3(1.1, 2.0);
cout << "The fx and fy of p3: "; //用构造函数point(double x, double y = 5.5)创建对象
p3.showpoint(); //fy被重新赋值为2.0
return 0;
}
输出:
The fx and fy of p1: 0 0
The fx and fy of p2: 1 5.5
The fx and fy of p3: 1.1 2
上述代码中,类point中声明了两个构造函数:point()和point(double x, double y)。在main()函数中声明对象时,系统自动调用相应的构造函数,如在point p1;语句中声明p1对象时,调用的是point()构造函数。