108讲-拷贝构造函数调用时机–构造函数调用规则–深拷贝与浅拷贝–初始化列表
内容纲要

拷贝构造函数调用时机

C++ 中拷贝构造函数调用时机通常有三种情况:

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

详细笔记请看下方代码
笔记全在代码之中!!

  • 注意:
    值传递的时候是生成副本,会(自动)调用拷贝函数。
    返回值时,也是返回副本,也会(自动)调用拷贝函数。
#include <iostream>
using namespace std;

class Person{
public:
    Person() {
        cout << "Person 默认构造函数被调用~" << endl;
    }
    Person(int x) {
        m_Age = x;
        cout << "  Person  有参构造函数被调用~~ age = " << m_Age <<  endl;
    }
    Person(const Person& p) {
        m_Age = p.m_Age;
        cout << "    Person   拷贝构造函数被调用~~~ age = " << m_Age << endl;
    }
    int m_Age;

    ~Person() {

        cout << "~~析构函数被调用~~~喵~~~" << endl;
    }
};
class Person2 {  //测试当一个函数销毁时,多个对象的析构函数 是否有先后执行顺序。
public:
    Person2() {
        cout << "Person2 默认构造函数被调用~" << endl;
    }

    ~Person2() {
        cout << "Person2 析构函数被调用" << endl;
    }
};

//拷贝构造函数调用时机

    //1.使用一个已经创建完毕的对象来初始化一个新对象
void test01() {
    Person p2(10);
    Person p3(p2); //使用已经创建好的对象 来初始化另外一个新对象。
}

    //2.值传递的方式给函数参数传值
void doWork2(Person p) {   //值传递 是会将值生成一个副本,在局部变量中修改其内容,并不会影响它本身。

}
void test02() {
    Person p1;
    doWork2(p1);  //这里会拷贝一份,我个人理解就是 doWork(Person p = p1){ } 在这里执行的显式调用拷贝构造函数。
                 //如果将其拷贝构造函数注释掉,test02() 函数执行完之后依旧会调用 两次 析构函数。
}

    //3.值方式返回局部对象。
Person doWork03() {
    Person p1(10);
    cout << "p1的地址为:  " << (int*)&p1 << endl;
    return p1;   //返回时会拷贝它自己一份。
}
void test03() {
    Person p = doWork03();
    //doWork03();    //如果没人接收它,它就会被系统立即回收。。可以用析构函数出现的位置来证明。
    cout << "p的地址为:  "  << (int*)&p << endl;   //这里的地址和 doWork03() 创建的对象 地址不一样!!!
}

void main() {
    test03();
}

构造函数调用规则

默认情况下,c++ 编译器至少给一个类添加3 个函数。

  1. 默认构造函数(无参,函数体为空)
  2. 默认析构函数(无参,函数体为空)
  3. 默认拷贝构造函数,对属性经行值拷贝

构造函数调用规则:

  • 如果用户定义有参构造函数,C++ 不再提供默认无参构造,但会提供默认拷贝构造。
  • 如果用户定义拷贝构造函数,C++ 不会再提供其它构造函数(包括无参构造函数)
    file

深拷贝、浅拷贝

浅拷贝:简单的赋值拷贝操作。

深拷贝:在堆区重新申请空间,进行拷贝操作

  • 浅拷贝问题点。
    file

//下方代码运行时会报错。因为析构函数将浅拷贝的内存地址西沟了,但是在拷贝函数中再析构一次时,对象已经置空,就会报错。

#include <iostream>
using namespace std;

class Student
{
public:
    Student() {
        cout << "Student默认构造函数被调用" << endl;
    }

    Student(int age,int Height) {

        m_Height =  new  int(Height);

        m_age = age;
        cout << "Student有参构造器被调用" << endl;
        cout << "Stu的年龄为: " << m_age << endl <<
            "Stu年龄的地址为:" << (int*)m_age << endl;
    }
    Student(const Student& stu) {   //拷贝构造函数
        m_Height = stu.m_Height;
        m_age = stu.m_age;
        cout << "Student拷贝构造函数被调用" << endl;
    }

    ~Student() {

        if (m_Height != NULL)
        {
            delete(m_Height);
            m_Height = NULL;
        }

        cout << "Student析构函数被调用" << endl;
    }

    int m_age;
    int* m_Height;

};

void test() {
    Student stu(18,160);

    Student stu_copy(stu);
    cout << "stu_copy 的年龄为:" << stu_copy.m_age << endl <<
        "stu_copy中年龄的地址为:" << (int*)stu_copy.m_age << endl;

}

void main() {

    test();
}

//析构代码:养成一个好习惯,在堆中开辟的空间要主动释放,并将对象置空。

    ~Student() {

        if (m_Height != NULL)
        {
            delete(m_Height);
            m_Height = NULL;
        }

        cout << "Student析构函数被调用" << endl;
    }
  • 问题点解决办法:使用深拷贝来解决。
    file

总结:如果有属性需要在堆中开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题。

初始化列表

作用:

C++ 提供了初始化列表语法,用来初始化属性

语法:构造函数():属性1(值1),属性2(值2)...{}

file

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇