构造函数
C++中的类和对象对应了C语言中的结构体和结构体变量。
在C语言中,我们应该养成变量初始化的习惯。
以下我们无法从语法上检查出,不初始化的错误:
struct tagClock{
int iHour;
int iMin;
int iSec; 5
};
int main(int argc, char* argv[])
{
tagClock timer1;
printf("%02d:%02d:%02d\r\m", timer1.iHour,
timer1.iMin,
timer1.iSec);
return 0;
}
C++中为了可以更方便地初始化对象,提出了构造函数的概念。
构造函数概念
构造函数是帮助我们自动初始化对象的函数。
构造函数的原理
- 定义类时,定义了构造函数
- 构造函数内部,可以对变量进行操作(因为构造函数也是一个方法,有this指针)
- 编译器,会在变量生命周期的开始,自动调用这个类的构造函数
构造函数的语法
构造函数也是一个类中的方法。所以它的定义语法,与普通类方法非常相似。要声明一个类的构造函数,只需要在类中写:
类名(参数列表)
{
函数实现体
}
实例:
struct tagClock{
int iHour;
int iMin;
int iSec;
tagClock(){
iHour = 0;
iMin = 0;
iSec = 0;
}
tagClock(int hour, int min, int sec){
iHour = hour;
iMin = min;
iSec = sec;
}
void Show(){
printf("%02d:%02d:%02d\r\n", iHour,
iMin,
iSec);
}
};
int main(int argc, char* argv[])
{
tagClock timer1(20, 12, 5);
tagClock timer2;
timer1.Show();
timer2.Show();
return 0;
}
总结:
- 构造函数的名字必须与类名相同
- 构造函数不能有返回值
- 构造函数是可以重载的
- 构造函数不可以被显式调用,如以下方法调用,无法通过编译:
tagClock timer1;
timer1.tagClock(); //编译不通过,不能显式调用
并且,为了照顾大家的写法习惯,C++中初始化变量时,以下的写法,其实也是调用构造函数:
tagClock timer1 = { 20, 12, 5 };
//等价于tagClock timer1(20, 12, 5);
拷贝构造及其意义
在C语言中,我们可以将同类型的,一个结构体变量,赋值给另外一个结构体变量。
如:
struct tagClock{
int iHour;
int iMin;
int iSec;
};
int main(int argc, char* argv[])
{
struct tagClock timer1 = { 20, 12, 5 };
struct tagClock timer2 = timer1;
return 0;
以上的赋值过程,其实相当于:
memcpy(&timer2, &timer1, sizeof(struct tagClock));
以上,虽然方便,但是灵活度不够。所以,C++提供了拷贝构造。它是一种较为特殊的构造,其触发的条件有两条:
- 发生在对象生命周期开始
- 拷贝构造的参数,必须是同类型的类的引用比如以下实例:
struct tagClock
{
int iHour;
int iMin;
int iSec;
tagClock(){
iHour = 0;
iMin = 0;
iSec = 0;
}
tagClock(int argHour, int argMin, int argSec){
iHour = argHour;
iMin = argMin;
iSec = argSec;
}
tagClock(tagClock& otherClock){//拷贝构造
printf("我是拷贝构造\r\n");
iHour = otherClock.iHour+1;
iMin = otherClock.iMin;
iSec = otherClock.iSec;
}
void Show(){
printf("%02d:%02d:%02d\r\n", iHour,
iMin,
iSec);
}
};
int main(int argc, char* argv[])
{
struct tagClock timer1 = { 20, 12, 5 };
struct tagClock timer2(timer1);
timer1.Show();
timer2.Show();
return 0;
}
如果我们不实现拷贝构造,则编译器会自动生成一个拷贝构造,其作业等同于memcpy(其实是为了完全兼容C)
拷贝构造的其它发生时机
- 把对象作为参数进行值传递
void Fun(tagClock myclock)
{
myclock.Show();
}
int main(int argc, char* argv[])
{
struct tagClock timer1 = { 20, 12, 5 };
struct tagClock timer2(timer1);
timer1.Show();
timer2.Show();
Fun(timer1);
return 0;
}
- 局部变量对象作为返回值返回时
tagClock Fun()
{
tagClock timer1(10, 10, 0);
return timer1;
}
int main(int argc, char* argv[])
{
printf("%d", Fun().iHour);
tagClock timer2 = Fun();
return 0;
}
注意将对象的引用或者指针作为参数传递,不会发生拷贝构造。如:
void Fun(tagClock& timer)
{
timer.Show();
}
int main(int argc, char* argv[])
{
tagClock timer(10, 10, 10);
Fun(timer);
return 0;
}