------------------------------------------------
1.设置六个函数的参数,先让函数运行起来
1.1 test/Student.h
#include
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
#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
//--------------------------------------------------------------------------------
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
#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