C++类的六个特殊成员函数20220226

------------------------------------------------

1.设置六个函数的参数,先让函数运行起来

1.1 test/Student.h

#include <iostream>

class Stu {

private:
    std::string name = "无名氏";
    int age = 18;

public:
    Stu();

    Stu(std::string name, int age);

    Stu(const Stu &s);

    Stu(Stu &&s);

    Stu &operator=(const Stu &s);

    Stu &operator=(Stu &&s);

    ~Stu();

};

1.2 test/Student.cpp

#include "Student.h"

Stu::Stu() { std::cout << "执行了无参构造函数!" << std::endl; };

Stu::Stu(std::string name, int age) { std::cout << "执行了有参构造函数!" << std::endl; };

Stu::Stu(const Stu &s) { std::cout << "执行了拷贝构造函数!" << std::endl; };

Stu::Stu(Stu &&s) { std::cout << "执行了移动构造函数!" << std::endl; };

Stu &Stu::operator=(const Stu &s) { std::cout << "执行了拷贝赋值运算符函数!" << std::endl; };

Stu &Stu::operator=(Stu &&s) { std::cout << "执行了移动赋值运算符函数!" << std::endl; };

Stu::~Stu() { std::cout << "执行了析构函数!" << std::endl; };

1.3 test/C++类的六个特殊成员函数.cpp

#include <iostream>

#include "Student.h"     // TODO 这个必须要加

int main() {

    // 类的六个特殊成员函数总结如下:
    // 普通构造函数(无参构造函数:Stu()、有参构造函数:Stu(std::string name, int age))
    // 拷贝构造函数:Stu(const Stu &s)
    // 移动构造函数:Stu(Stu &&s)
    // 拷贝赋值运算符函数:Stu &operator=(const Stu &s)
    // 移动赋值运算符函数:Stu &operator=(Stu &&s)
    // 析构函数:~Stu()

    Stu s1;

    Stu s2("张三", 28);

    Stu s3 = s2;

    Stu s4 = std::move(s3);

    Stu s5;
    s5 = s4;

    Stu s6;
    s6 = std::move(s5);

    std::cout << std::endl << "执行了main函数" << std::endl << std::endl;

    return 0;
}

1.4 输出结果

/home/liuhao/CLionProjects/Robot_modules_cpp/cmake-build-debug/bin/class_function
执行了无参构造函数!
执行了有参构造函数!
执行了拷贝构造函数!
执行了移动构造函数!
执行了无参构造函数!
执行了拷贝赋值运算符函数!
执行了无参构造函数!
执行了移动赋值运算符函数!

执行了main函数

执行了析构函数!
执行了析构函数!
执行了析构函数!
执行了析构函数!
执行了析构函数!
执行了析构函数!

Process finished with exit code 0

------------------------------------------------

2.六个函数的具体功能实现

2.1 test/Student.h

#include <iostream>


//--------------------------------------------------------------------------------
class AA {

private:
    std::string name = "";
    int *AA_d = nullptr;

public:
    explicit AA(std::string name) {      // 单一参数的构造函数最好加上explicit,避免隐式转换
        this->name = name;

        AA_d = new int(666);        // TODO 这里要给定指向,因为后面有*AA_d

        std::cout << this->name << " " << "执行了无参构造函数!" << std::endl;
        std::cout << this->name << " " << "指针指向的地址:" << AA_d << std::endl;
        std::cout << this->name << " " << "指针指向的地址的内容:" << *AA_d << std::endl;
        std::cout << this->name << " " << "指针自身的地址:" << &AA_d << std::endl;
        std::cout << "----------------------------------" << std::endl;
    };

    ~AA() {
        delete AA_d;
        AA_d = nullptr;

        std::cout << name << " " << "执行了析构函数!" << std::endl;
    };
};
//--------------------------------------------------------------------------------






class Stu {

public:
    std::string name = "无名氏";
    int age = 18;
    int *point = nullptr;

    AA *p_internal = nullptr;   // TODO 1.指向内部生成的内部对象,要在析构函数里面先释放后置空;
    AA *p_external = nullptr;   // TODO 2.指向外部传递的外部对象,不用在析构函数里面管理;

public:
    //==========================================================
    Stu();

    Stu(std::string name, int age, AA *p_temp);

    //==========================================================
    Stu(const Stu &s);

    //==========================================================
    Stu &operator=(const Stu &s);

    //==========================================================
    Stu(Stu &&s) noexcept;

    //==========================================================
    Stu &operator=(Stu &&s) noexcept;

    //==========================================================
    ~Stu();
    //==========================================================




    //==========================================================
    Stu &operator&&(const Stu &s);
    //==========================================================

};

2.2 test/Student.cpp

#include "Student.h"

//=================================================================================
Stu::Stu() {
    name = "s1";
    age = 1;
    // TODO s1是空指针,虽然没有new,但是析构函数可以用delete,因为会判断是否为空
    std::cout << name << " " << age << " " << "执行了无参构造函数!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << "空指针没有指向,不能解引用操作" << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;
};

Stu::Stu(std::string name, int age, AA *p_temp) {
    this->name = "s2";  // 没有用name赋值,是为了显示
    this->age = 2;      // 没有用age赋值,是为了显示

    point = new int(888);

    std::cout << this->name << " " << this->age << " " << "执行了有参构造函数!" << std::endl;
    std::cout << this->name << " " << this->age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << this->name << " " << this->age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << this->name << " " << this->age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;

    p_internal = new AA(name);  // TODO 1.指向内部生成的内部对象,要在析构函数里面先释放后置空;

    if (p_temp == nullptr) {
        p_external = nullptr;
    } else {
        p_external = p_temp;    // TODO 2.指向外部传递的外部对象,不用在析构函数里面管理;
        p_temp = nullptr;       // 防止两个指针指向同一块内存
    }

};


//=================================================================================
Stu::Stu(const Stu &s) {
    name = "s3";
    age = 3;

    if (s.point == nullptr) {
        point = nullptr;
    } else {
        //开辟新的空间
        point = new int();      // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
        //把原来的值,拷贝过来。
        *point = *s.point;          // TODO 注意s不能是空指针,比如s1
    }

    std::cout << name << " " << age << " " << "执行了拷贝构造函数(深拷贝)!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;
};


//=================================================================================
Stu::Stu(Stu &&s) noexcept {     // noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。
    name = "s4";
    age = 4;                // 移动赋值运算符函数,那这个s.name和s.age怎么处理的啊

    if (s.point == nullptr) {
        point = nullptr;
    } else {
        // s的指向的地址赋值给当前对象this
        point = s.point;
        // s需要置空,断开指向,避免2个指针指向同一块空间
        s.point = nullptr;
    }
    std::cout << name << " " << age << " " << "执行了移动构造函数!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;
};


//=================================================================================
Stu &Stu::operator=(const Stu &s) {
    name = "s5";
    age = 5;

    if (s.point == nullptr) {
        point = nullptr;
    } else {
        //开辟新的空间
        point = new int();      // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
        //把原来的值,拷贝过来。
        *point = *s.point;          // TODO 注意s不能是空指针,比如s1
    }
    std::cout << name << " " << age << " " << "执行了拷贝赋值运算符函数!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;

    return *this;
};


//=================================================================================
Stu &Stu::operator=(Stu &&s) noexcept {     // noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。
    name = "s6";
    age = 6;                // 移动赋值运算符函数,那这个s.name和s.age怎么处理的啊

    if (s.point == nullptr) {
        point = nullptr;
    } else {
        // s的指向的地址赋值给当前对象this
        point = s.point;
        // s需要置空,断开指向,避免2个指针指向同一块空间
        s.point = nullptr;
    }
    std::cout << name << " " << age << " " << "执行了移动赋值运算符函数!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;

    return *this;
};


//=================================================================================
Stu::~Stu() {
    delete point;
    point = nullptr;

    std::cout << name << " " << age << " " << "执行了析构函数!" << std::endl;

    delete p_internal;
    p_internal = nullptr;
};
//=================================================================================




//**********************************************************************************
Stu &Stu::operator&&(const Stu &s) {     // 重新定义了&&运算符(DIY)
    name = "s9";
    age = 9;

    if (s.point == nullptr) {
        point = nullptr;
    } else {
        //开辟新的空间
        point = new int();      // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
        //把原来的值,拷贝过来。
        *point = *s.point;          // TODO 注意s不能是空指针,比如s1
    }
    std::cout << name << " " << age << " " << "执行了拷贝赋值运算符函数!" << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址:" << point << std::endl;
    std::cout << name << " " << age << " " << "指针指向的地址的内容:" << *point << std::endl;
    std::cout << name << " " << age << " " << "指针自身的地址:" << &point << std::endl;
    std::cout << "----------------------------------" << std::endl;

    return *this;
};
//**********************************************************************************

2.3 test/C++类的六个特殊成员函数.cpp

#include <iostream>

#include "Student.h"     // TODO 这个必须要加

int main() {

    // 类的六个特殊成员函数总结如下:
    // 普通构造函数(无参构造函数:Stu()、有参构造函数:Stu(std::string name, int age, AA *p_temp))
    // 拷贝构造函数:Stu(const Stu &s)
    // 移动构造函数:Stu(Stu &&s)
    // 拷贝赋值运算符函数:Stu &operator=(const Stu &s)
    // 移动赋值运算符函数:Stu &operator=(Stu &&s)
    // 析构函数:~Stu()

    //=================================================================================
    AA aa("外部对象");

    //=================================================================================
    Stu s1;                         // 无参构造函数,里面有空指针;
    Stu s2("内部对象", 100, &aa);    // 有参构造函数

    //=================================================================================
    Stu s3 = s2;                    // 拷贝构造函数(深拷贝)        // 不能用s1,里面有空指针呢;

    //=================================================================================
    Stu s4 = std::move(s3);              // 移动构造函数               // 不能用s1,里面有空指针呢;
//    // TODO s3竟然还可以再用
//    std::cout << "**************** " << s3.point << std::endl;      // 0
//    std::cout << "**************** " << s3.name << std::endl;       // s3
//    std::cout << "**************** " << s3.age << std::endl;        // 3

    //=================================================================================
    Stu s5;
    s5 = s4;                        // 拷贝赋值运算符函数          // 不能用s1,里面有空指针呢;

    //=================================================================================
    Stu s6;
    s6 = std::move(s5);                  // 移动赋值运算符函数        // 不能用s1,里面有空指针呢;
//    // TODO s5竟然还可以再用
//    std::cout << "**************** " << s5.point << std::endl;      // 0
//    std::cout << "**************** " << s5.name << std::endl;       // s4
//    std::cout << "**************** " << s5.age << std::endl;        // 4

    //=================================================================================
    Stu s9;
    s9 && s6;                       // 重新定义了&&运算符(DIY)

    s9 && s6 && s4 && s2;           // 运算符多次重载
//    s9 && s6 && s3 && s2 && s1;   // s1里面有空指针,不能参与运算符多次重载,因为operator&&函数里面有解引用操作

    //=================================================================================

    std::cout << "=======================================执行了main函数" << std::endl;

    return 0;
}

2.4 输出结果

/home/liuhao/CLionProjects/Robot_modules_cpp/cmake-build-debug/bin/class_function
外部对象 执行了无参构造函数!
外部对象 指针指向的地址:0x1907c20
外部对象 指针指向的地址的内容:666
外部对象 指针自身的地址:0x7ffdf188c390
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7ffdf188c3c8
----------------------------------
s2 2 执行了有参构造函数!
s2 2 指针指向的地址:0x1908050
s2 2 指针指向的地址的内容:888
s2 2 指针自身的地址:0x7ffdf188c408
----------------------------------
内部对象 执行了无参构造函数!
内部对象 指针指向的地址:0x19080a0
内部对象 指针指向的地址的内容:666
内部对象 指针自身的地址:0x1908090
----------------------------------
s3 3 执行了拷贝构造函数(深拷贝)!
s3 3 指针指向的地址:0x19080c0
s3 3 指针指向的地址的内容:888
s3 3 指针自身的地址:0x7ffdf188c448
----------------------------------
s4 4 执行了移动构造函数!
s4 4 指针指向的地址:0x19080c0
s4 4 指针指向的地址的内容:888
s4 4 指针自身的地址:0x7ffdf188c488
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7ffdf188c4c8
----------------------------------
s5 5 执行了拷贝赋值运算符函数!
s5 5 指针指向的地址:0x19080e0
s5 5 指针指向的地址的内容:888
s5 5 指针自身的地址:0x7ffdf188c4c8
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7ffdf188c508
----------------------------------
s6 6 执行了移动赋值运算符函数!
s6 6 指针指向的地址:0x19080e0
s6 6 指针指向的地址的内容:888
s6 6 指针自身的地址:0x7ffdf188c508
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7ffdf188c548
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1908100
s9 9 指针指向的地址的内容:888
s9 9 指针自身的地址:0x7ffdf188c548
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1908120
s9 9 指针指向的地址的内容:888
s9 9 指针自身的地址:0x7ffdf188c548
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1908140
s9 9 指针指向的地址的内容:888
s9 9 指针自身的地址:0x7ffdf188c548
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1908160
s9 9 指针指向的地址的内容:888
s9 9 指针自身的地址:0x7ffdf188c548
----------------------------------
=======================================执行了main函数
s9 9 执行了析构函数!
s6 6 执行了析构函数!
s5 5 执行了析构函数!
s4 4 执行了析构函数!
s3 3 执行了析构函数!
s2 2 执行了析构函数!
内部对象 执行了析构函数!
s1 1 执行了析构函数!
外部对象 执行了析构函数!

Process finished with exit code 0
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值