1.构造函数:创建对象时为对象的成员变量赋值,构造函数由编译器自动调用,无需手动调用
1.没有返回值也不用写void
2.函数名称与类的名称相同
3.构造函数有参数,因此可以发生重载
4.程序在调用对象时会自动调用构造,无需手动调用,而且只会调用一次
2.构造函数的调用顺序为
- 调用基类构造函数;
- 调用自对象构造函数;
- 最后执行派生类构造函数本身。
3.对象销毁前会自动调用构造,无需手动调用,而且只会调用一次
1.没有返回值也不用写void
2.函数名称与类的名称相同,在名称前面加上~
3.构造函数没有参数,因此不可以发生重载
4.程序在对象销毁前会自动调用构造,无需手动调用,而且只会调用一次
#include <iostream>
using namespace std;
class person
{
private:
int age;
public:
person()
{
cout << "无参构造函数的调用" << endl;
}
person(int m)
{
age = m;
cout << "有参构造函数的调用" << endl;
}
person(const person &p) //注意格式
{
age = p.age;
cout << "拷贝构造函数的调用" << endl;
}
~person()
{
cout << "析构函数的调用" << endl;
}
void display(void)
{
cout << "age = " << age << endl;
}
};
int main(void)
{
person p1; //无参构造函数的调用,注意这里不要加括号
person p2(3); //有参构造函数的调用方法1
p2.display();
person p21 = person(3); //有参构造函数的调用方法2
//person(3)称为匿名对象,上面那行就是给匿名对象起名字,单独的匿名对象在当前行结束之后就会释放
p21.display();
person p22 = 4; //有参构造函数的调用方法3
p22.display();
person p3(p2); //拷贝构造函数的调用方法1
p3.display();
person p31 = person(p2); //拷贝构造函数的调用方法2
p31.display();
person p32 = p2; //拷贝构造函数的调用方法3
p32.display();
}
4.拷贝构造函数的使用场景
#include <iostream>
using namespace std;
class person
{
private:
int age;
public:
person()
{
cout << "默认构造函数调用" << endl;
}
person(int a)
{
age = a;
cout << "构造函数调用" << endl;
}
~person()
{
cout << "析构函数调用" << endl;
}
person(const person &p)
{
age = p.age;
cout << "拷贝构造函数调用" << endl;
}
void display(void)
{
cout << "age = " << age << endl;
}
};
void test1(void) //1.使用一个已经创建完毕的对象来初始化一个新的对象
{
person p1(20);
person p2(p1);
}
void func1(person p) //2.以值传递的方式给一个参数传递值
{
p.display();
}
void test2(void)
{
person p(10);
func1(p);
}
person func2(void) //3.以函数返回值的方式
{
person p(10);
return p;
}
void test3()
{
person p;
p = func2();
p.display();
}
int main(void)
{
//test1();
//test2();
test3();
return 0;
}
5.构造函数的调用规则
1.默认情况下编译器会给程序添加三个构造函数:
默认构造函数(无参,函数体为空)
默认析构函数(无参,函数体为空)
默认拷贝构造函数,对成员变量进行值拷贝
2.如果用户定义有参构造函数,编译器不再提供无参构造函数,但是会提供默认拷贝构造函数
3.如果用户定义拷贝构造函数,编译器不再提供其他构造函数(有参构造函数和无参构造函数)
6.深拷贝与浅拷贝的问题
浅拷贝就是简单的赋值拷贝,而当成员变量是指针的时候,进行浅拷贝也会将该成员变量的值(地址)拷贝给新的
对象,从而在析构函数中造成重复释放空间的问题,因此重新定义一个深拷贝函数,重新在堆中申请一块内存,存
放相同的值,但是此时成员变量的值(地址)不同,也就不会造成析构函数中重复释放空间的问题
因此类中如果有指针成员变量则必须自己定义拷贝构造函数
#include <iostream>
using namespace std;
class person
{
private:
int age;
int *height;
public:
person()
{
cout << "默认构造函数调用" << endl;
}
person(int a, int h)
{
age = a;
height = new int(h);
cout << "构造函数调用" << endl;
}
~person()
{
if(height != NULL)
{
delete(height);
height = NULL;
}
cout << "析构函数调用" << endl;
}
person(const person &p)
{
age = p.age;
// height = p.height; //这是浅拷贝,就是编译器默认的拷贝构造函数的语句
height = new int(*p.height); //这是深拷贝,在堆区重新申请空间,进行拷贝操作
cout << "拷贝构造函数调用" << endl;
}
void display(void)
{
cout << "age = " << age << endl;
cout << "height = " << *height << endl;
}
};
void test1(void)
{
person p1(20, 160);
person p2(p1);
p1.display();
p2.display();
}
int main(void)
{
test1();
return 0;
}
- 派生类只能采用构造函数初始化列表的方式向基类或成员对象的构造函数传递参数,
class D : public B {
public:
C c1, c2;
A* a1 = new A(10);
A a0, a4;
D() : a4(4), c2(2), c1(1), B(1) { //初始化列表的形式传递参数给另一边的构造函数
cout << "D-----5" << endl;
}
};