1、构造函数概述
在c++程序中对象的初始化是一个不可缺少而十分重要的内容。为了对对象进行初始化,c++提供了构造函数来处理对象的初始化,构造函数是一种特殊的成员函数,与其他函数不同,构造函数时在建立对象时自动执行。
构造函数的作用:对象的初始化
构造函数的调用:由编译器自动调用
构造函数的调用时机:在创建对象时,系统会为该对象分配内存空间,并调用构造函数进行初始化
构造函数的要求:函数名与类名相同(以便编译器能够识别它,把它当作构造函数来处理),没有类型,不返回任何值。
注意:
1.如果用户没有自己定义构造函数,则c++系统会自动生成一个构造函数,只是这个构造函数的函数体是空的,也没有参数,不执行初始化操作。
2.构造函数可以重载
3.构造函数可以有默认参数
4.构造函数的重载与默认一般不同时使用,以免造成二义性问题。
5.如果用户自定义构造函数,系统不会指自动产生默认构造,但是会产生拷贝构造。
6.如果用户自定义拷贝构造,系统不会提供其他构造函数
2、构造函数的分类及调用
按参数分为
1.无参构造函数
2.有参构造函数
按类型分为
1.普通构造
2.拷贝构造
三种调用
1.括号发
2.显示发
3.隐士转换法
#include <iostream>
using namespace std;
class person
{
public:
person()
{
cout << "person的无参构造调用" << endl;
}
person(int a)
{
age = a;
cout << "person的有参构造调用" << endl;
}
person(const person &p)
{
age =p.age;
cout << "person的拷贝构造调用" << endl;
}
~person()
{
cout << "person的析构调用" << endl;
}
int age;
};
void test01()
{
//括号法
person p1;//注意不要加(),否则会被认为函数声明
person p2(100);
person p3(p2);
//显示法
person p4;//注意不要加(),否则会被认为函数声明
person p5=person(100);//如果将person(100)单独拿出来,就是匿名对象
person p6=person(p5);
//隐士转换法法
person p7;//注意不要加(),否则会被认为函数声明
person p8=100;//person p8=person(100);
person p9=p8; //person p9 = person(p8);
}
int main()
{
test01();
return 0;
}
3、用初始化列表来初始化对象
person(int a):age(a)
{
age = a;
cout << "person的有参构造调用" << endl;
}
注意:用初始化列表进行初始化时,数据成员不能是数组,如果数据成员包含数组,则必须用函数体对数组进行初始化。
4、构造函数的重载
说明:
1.在建立对象时不必给出实参的构造函数称为默认构造函数。显然无参构造函数属于默认构造函数,一个类只能有一个默认构造函数,如果用户没有自定义构造函数,系统会自动产生一个默认构造函数,但是它的函数体是空的,不起初始化作用。
2.如果在建立对象时选用的时无参构造,则要注意其写法。
person p4;//注意不要加(),否则会被认为函数声明
3.尽管在一个类中可以有多个构造函数,但是对于每一个对象来说,只执行其中一个构造函数,并非每个构造函数都会被执行。
5、使用默认参数的构造函数
说明:
1.应该在构造函数声明的地方指定默认值,而不是只在定义构造函数时指定默认值。
2.在声明构造函数时,形参名称可以省略
3.如果全部参数都有默认值,则不用在写无参构造。
4.一般在使用默认参数的构造函数后,不应再使用函数重载,以免产生二义性问题。
6、对象的赋值和复制
一.对象的赋值
对象的赋值与普通变量的一样,赋值的一般形式
对象名1=对象名2;
注意这里的=本来只可以对单个变量的赋值,但是由于c++提供了运算符重载功能,使用=可以用于两个同类对象的赋值。
说明:
1.对象的赋值只对其中数据成员赋值,而不对数据对象赋值。
2.类的数据成员中不能包括动态分配的数据,否则在赋值时可能会出现严重后果。
二.对象的复制
复制的一般形式
类名 对象2(对象1);等价于
类名 对象2=对象1;
对象的复制是调用拷贝构造函数实现的。
总结:
对象赋值是对一个已经存在的对象赋值,因此必须先定义被赋值的对象,才能进行赋值。而对象的复制则是从无到有地建立一个新对象,并使它与一个已有对象完全相同(包括对象的结构和成员的值)
7、拷贝构造的调用时机
1.使用一个已经创建好的对象来初始化一个新对象
2.当函数的参数为类的对象
void fun(Person p){}
int main()
{
Person p1(10);
fun(p1);
return 0;
}
3.函数的返回值时类对象
person fun()
{
person p(10);
rtunrn p;
}
int main()
{
person p1;
p1=fun();
return 0;
}
8、深拷贝与浅拷贝
浅拷贝:简单的赋值拷贝
深拷贝:在堆区申请空间,进行拷贝操作
浅拷贝带来的问题是堆区内存的重复释放。
解决方法是用深拷贝,在堆区重新开辟一段内存。
#include <iostream>
using namespace std;
class person
{
public:
person(int a,int b)
{
age = a;
height = new int(b);
cout << "person的有参构造调用" << endl;
}
//深拷贝
person(const person &p)
{
age =p.age;
height = new int(*p.height);
cout << "person的拷贝构造调用" << endl;
}
~person()
{
if (height != NULL)
{
delete height;
height=NULL;
}
cout << "person的析构调用" << endl;
}
int age;
int* height;
};
void test01()
{
person p(18,180);
cout << p.age<<"\t" << *p.height << endl;
person p2(p);
cout << p2.age<<"\t" << *p2.height << endl;
}
int main()
{
test01();
return 0;
}