第9课 - 构造函数
一.对象的初始化
1.1 对每个类都提供一个public的initialize函数
对象创建后立即调用initialize函数进行初始化
Source Example 1.1:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test {
private:
int i;
public:
void initialize()
{
i = 0;
}
int geti()
{
return i;
}
};
int main(int argc, char** argv) {
Test test1;
test1.initialize();
/* 输出结果为0 */
printf ("%d\n", test1.geti());
return 0;
}
方案缺点:
initialize只是一个普通的函数,必须显示的调用。
一旦由于失误的原因,对象没有初始化,那么结果将是不确定的。
1.2 C++中的构造函数
1.2.1 C++中的类可以定义与类名相同的特殊成员函数
1.2.2 这种类名相同的成员函数叫做构造函数
1.2.3 构造函数在定义时可以有参数,但是没有任何返回类型的声明(与返回值为void完全不同)
1.2.4 一般情用
Source Example 1.2:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test {
private:
int i;
int j;
int k;
public:
Test (int v) /* 构造函数 */
{
i = j = k = v;
}
int print()
{
printf ("i = %d, j = %d, k = %d\n", i,j,k);
}
};
int main(int argc, char** argv) {
Test test1(4); /* 自动初始化 */
Test test2 = 5; /* 自动初始化 */
Test test3 = Test(6); /* 手动初始化 */
/* 输出结果为:
i = 4,j = 5,k = 6
i = 4,j = 5,k = 6
i = 4,j = 5,k = 6 */
test1.print();
test2.print();
test3.print();
/* 定义了类的对象数组,必须手动初始化,否则编译报错 */
Test tA[3] = {Test(1), Test(2),Test(3)};
for (int i = 0; i < 3; i++)
{
/* 输出结果为:
i = 1,j = 2,k = 3
i = 1,j = 2,k = 3
i = 1,j = 2,k = 3 */
tA[i].print();
}
return 0;
}
1.3 成员函数的重载
1.3.1 类的成员函数和普通函数一样可以重载,并遵守相同的重载规则
1.3.2 构造函数也是成员函数,也可以进行重载
Source Example 1.3:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test {
private:
int i;
int j;
int k;
public:
Test (int v)
{
i = j = k = v;
}
Test ()
{
i = 0;
j = 0;
k = 0;
}
int print()
{
printf ("i = %d, j = %d, k = %d\n", i,j,k);
}
int print(int v)
{
printf ("v = %d\n", v);
}
};
int main(int argc, char** argv) {
/* 会调用一个参数的构造函数来初始化 */
Test test1(4);
Test test2 = 5;
Test test3 = Test(6);
Test test4; /* 会调用没有参数的函数来初始化 */
/* 输出结果为:
i = 4,j = 5,k = 6
i = 4,j = 5,k = 6
i = 4,j = 5,k = 6
i = 0,j = 0,k = 0 */
test1.print();
test2.print();
test3.print();
test4.print();
/* 编译通过了,会调用没有参数的构造函数进行初始化 */
Test tA[3];
for (int i = 0; i < 3; i++)
{
/* 输出结果为:
i = 0,j = 0,k = 0
i = 0,j = 0,k = 0
i = 0,j = 0,k = 0 */
tA[i].print();
}
return 0;
}
1.4 两个特殊的构造函数
1.4.1 拷贝构造函数(参数为const引用)
当类中没有定义拷贝构造函数时,编译器默认提供一个拷贝构造函数,简单的进行成员变量的复制
1.4.2 默认构造函数(没有参数)
当类中没有定义构造函数时,编译器默认提供一个无参构造函数,并且其函数体为空
当自己写了任意一个构造函数之后,编译器就不会提供无参构造函数了
Source Example 1.4.1:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test {
public:
Test (const Test& v)
{
printf ("const int& v!\n");
}
Test ()
{
printf ("no paramts!\n");
}
/* 当使用该函数时,编译不过,因为编译器就不会提供默认构造函数,Test t1;在定义时没有提供初始化参数,就会出错
Test (const& Test v)
{
}
*/
};
int main(int argc, char** argv) {
/* 输出结果为
no paramts!
const int& v! */
Test t1;
Test t2 = 5;
return 0;
}
注意:
1.当类中没有定义任何一个构造函数,C++编译器会为我们提供无参构造函数和拷贝构造函数
2.当类中定义了任意非拷贝构造函数时,C++编译器就不会为我们提供无参构造函数
Source Example 1.4.2:
#include <iostream>
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
class Test {
private:
int i;
int j;
int k;
public:
void print()
{
printf("i = %d, j = %d, k = %d\n", i, j , k);
}
};
int main(int argc, char** argv) {
Test t1;
Test t2 = t1; /* 会调用拷贝构造函数将t1成员变量的值拷贝给t2的成员变量 */
/* 输出结果为:
i = 2031646, j = 0, k = 1
i = 2031646, j = 0, k = 1*/
t1.print();
t2.print();
return 0;
}
二.数组类的创建
Source Example 2:
/* array.h */
#ifndef _ARRAY_H_
#define _ARRAY_H_
class Array{
private:
int iLength;
int *pSpace;
public:
Array(int length);
int getLength();
void setData(int index, int data);
int getData(int index);
int destroy();
};
#endif /* _ARRAY_H_ */
/* array.c */
#include "array.h"
Array :: Array(int length)
{
iLength = length;
if (length > 0)
{
pSpace = new int[length];
}
}
int Array :: getLength()
{
return iLength;
}
void Array :: setData(int index, int data)
{
pSpace[index] = data;
}
int Array :: getData(int index)
{
return pSpace[index];
}
/* 自己提供的拷贝构造函数,具体原因见下列代码注释 */
Array :: Array(const Array& obj)
{
iLength = obj.iLength;
pSpace = new int[iLength];
for (int i = 0; i < iLength; i++)
{
pSpace[i] = obj.pSpace[i];
}
}
int Array :: destroy()
{
length = -1;
delete[] pSpace;
}
#include <iostream>
#include "array.h"
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
int main(int argc, char** argv) {
Array a(10);
for (int i = 0; i < 10; i++)
{
a.setData(i, i);
}
for (int j = 0; j < a.getLength(); j++)
{
printf ("%d\n", a.getData(j));
}
/* 通过构造函数将a的成员变量全部赋值给a2 */
/* 包括iLength,pSpace指向了同一片空间 */
Array a2 = a;
for (int j = 0; j < a2.getLength(); j++)
{
printf ("%d\n", a2.getData(j));
}
/* 释放空间的时候只能调用一个销毁函数,否则就会出错,解决方法就是自己提供一个拷贝构造函数 */
a.destroy();
a2.destroy();
return 0;
三.小结
3.1 构造函数是C++里面用于初始化对象的特殊函数
3.2 构造函数在对象创建时自动被调用
3.3 构造函数和普通成员函数都遵循重载规则
3.4 拷贝构造函数时对象正确初始化的重要保障