1.由来

类的数据成员不能在类的声明时候初始化,为了解决这个问题? 使用构造函数处理对对象的初始化。构造函数是一种特殊的成员函数,与其他函数不同,不需要用户调用它,而是创建对象的时候自动调用。析构函数是对象不再使用的时候,需要清理资源的时候调用。

2.基本语法

2.1构造函数

构造函数函数名和类名相同,没有返回值,不能有void,但可以有参数。

ClassName(){

}

2.2析构函数

析构函数函数名是在类名前面加”~”组成,没有返回值,不能有void,不能有参数,不能重载。

~ClassName(){

}

3.分类和调用

按参数类型:分为无参构造函数和有参构造函数

按类型分类:普通构造函数和拷贝构造函数(复制构造函数)

class Person{
public:
    //默认构造函数
    Person(){
        cout << "默认构造函数!" << endl;
        mAge = 0;
    }
    //有参构造函数
    Person(int age){
        cout << "有参构造函数!" << endl;
        mAge = age;
}
    //拷贝构造函数(复制构造函数) 使用另一个对象初始化本对象
    Person(const Person& person){
        cout << "拷贝构造函数!" << endl;
        mAge = person.mAge;
    }
    //打印年龄
    void PrintPerson(){
        cout << "Age:" << mAge << endl;
    }
private:
    int mAge;
};
//1. 无参构造调用方式
void test01(){

    //调用无参构造函数
    Person person1; 
    person1.PrintPerson();

    //无参构造函数错误调用方式
    //Person person2();
    //person2.PrintPerson();
}
//2. 调用有参构造函数
void test02(){

    //第一种 括号法,最常用
    Person person01(100);
    person01.PrintPerson();

    //调用拷贝构造函数
    Person person02(person01);
    person02.PrintPerson();

    //第二种 匿名对象(显示调用构造函数)
    Person(200); //匿名对象,没有名字的对象

    Person person03 = Person(300);
    person03.PrintPerson();

    //注意: 使用匿名对象初始化判断调用哪一个构造函数,要看匿名对象的参数类型
    Person person06(Person(400)); //等价于 Person person06 = Person(400);
    person06.PrintPerson();

    //第三种 =号法 隐式转换
    Person person04 = 100; //Person person04 =  Person(100)
    person04.PrintPerson();

    //调用拷贝构造
    Person person05 = person04; //Person person05 =  Person(person04)
    person05.PrintPerson();
}

注意:不能调用拷贝构造函数去初始化匿名对象,也就是说以下代码不正确:

    Person p1;
    Person(p1) //这种调用是错误的,因为Person(p1)等价于Person p1,编译器认为这是个函数声明

4.拷贝构造函数的调用方式

4.1.用已经创建好的对象来初始化新的对象

Person p1;
p1.m_Age = 10;
Person p2(p1)

4.2.以值传递的方式给函数参数传值

void fun(Person p1) //Person p1 = Person(p)
{
}
void main()
{
    Person p;
    p.m_Age = 10;
    fun(p);
}

4.3.以值方式返回局部对象

Person fun() 
{
    Person p1;
    return p1;
}
void main()
{
    Person p = fun();
}

注意:当环境设置为Release时,编译器会优化,例如:

Person fun() //原始代码
{
    Person p1;
    return p1;
}

void fun(Person & p1) //编译器优化完的代码
{
    Person p1;
}

构造函数的调用规则

默认情况下,c++编译器至少为我们写的类增加3个函数

  • 1.默认构造函数(无参,函数体为空)
  • 2.默认析构函数(无参,函数体为空)
  • 3.默认拷贝构造函数,对类中非静态成员属性简单值拷贝

如果用户定义拷贝构造函数,c++不会再提供任何默认构造函数

如果用户定义了普通构造(非拷贝),c++不在提供默认无参构造,但是会提供默认拷贝构造

5.浅拷贝和深拷贝

5.1浅拷贝

同一类型的对象之间可以赋值,使得两个对象的成员变量的值相同,两个对象仍然是独立的两个对象,这种情况被称为浅拷贝.

一般情况下,浅拷贝没有任何副作用,但是当类中有指针,并且指针指向动态分配的内存空间,析构函数做了动态内存释放的处理,会导致内存问题

5.2深拷贝

当类中有指针,并且此指针有动态分配空间,析构函数做了释放处理,往往需要自定义拷贝构造函数,自行给指针动态分配空间,深拷贝。

class Person{
public:
    Person(char* name,int age){
        pName = (char*)malloc(strlen(name) + 1);
        strcpy(pName,name);
        mAge = age;
    }
    //增加拷贝构造函数
    Person(const Person& person){
        pName = (char*)malloc(strlen(person.pName) + 1);
        strcpy(pName, person.pName);
        mAge = person.mAge;
    }
    ~Person(){
        if (pName != NULL){
            free(pName);
        }
    }
private:
    char* pName;
    int mAge;
};

void test(){
    Person p1("Edward",30);
    //用对象p1初始化对象p2,调用c++提供的默认拷贝构造函数
    Person p2 = p1;
}
最后修改:2024 年 07 月 17 日
如果觉得我的文章对你有用,请随意赞赏