1.设置六个函数的参数,先让函数运行起来
//
// Created by liuhao on 20-1-1.
//
#include <iostream>
//using namespace std;
class Stu {
private:
std::string name = "无名氏 ";
int age = 0;
int *d = nullptr;
public:
Stu() { std::cout << name << age << " 执行了无参构造函数!" << std::endl; };
Stu(int a) { std::cout << name << age << " 执行了有参构造函数!" << std::endl; };
Stu(const Stu &s) { std::cout << name << age << " 执行了拷贝构造函数!" << std::endl; };
Stu &operator=(const Stu &s) { std::cout << name << age << " 执行了拷贝赋值运算符函数!" << std::endl; };
Stu(Stu &&s) { std::cout << name << age << " 执行了移动构造函数!" << std::endl; };
Stu &operator=(Stu &&s) { std::cout << name << age << " 执行了移动赋值运算符函数!" << std::endl; };
~Stu() { std::cout << name << age << " 执行了析构函数!" << std::endl; };
};
int main() {
//=================================================================================
Stu s1;
Stu s2(100);
Stu s3 = s2;
Stu s4;
s4 = s3;
Stu s5 = std::move(s4);
Stu s6;
s6 = std::move(s5);
//=================================================================================
return 0;
}
1.输出结果
/home/liuhao/CLionProjects/Robot_modules_cpp/build/debug/bin/test/class_function
无名氏 0 执行了无参构造函数!
无名氏 0 执行了有参构造函数!
无名氏 0 执行了拷贝构造函数!
无名氏 0 执行了无参构造函数!
无名氏 0 执行了拷贝赋值运算符函数!
无名氏 0 执行了移动构造函数!
无名氏 0 执行了无参构造函数!
无名氏 0 执行了移动赋值运算符函数!
无名氏 0 执行了析构函数!
无名氏 0 执行了析构函数!
无名氏 0 执行了析构函数!
无名氏 0 执行了析构函数!
无名氏 0 执行了析构函数!
无名氏 0 执行了析构函数!
Process finished with exit code 0
2.六个函数的具体功能实现
//
// Created by liuhao on 20-1-1.
//
#include <iostream>
//using namespace std;
//=================================================================================
class AA {
private:
std::string name = "";
int age = 0;
int *d = nullptr;
public:
explicit AA(std::string name) { // 单一参数的构造函数最好加上explicit,避免隐式转换
this->name = name;
age = 123;
d = new int(456); // 这里要给定指向,因为后面有*AA_d
std::cout << this->name << age << " 执行了无参构造函数!" << std::endl;
std::cout << this->name << age << " 指针指向的地址:" << d << std::endl;
std::cout << this->name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << this->name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
};
~AA() {
delete d;
d = nullptr;
std::cout << name << age << " 执行了析构函数!" << std::endl;
};
};
//=================================================================================
class Stu {
public:
std::string name = "无名氏 ";
int age = 0;
int *d = nullptr;
AA *p_internal = nullptr; // 指向内部生成的内部对象,要在析构函数里面先释放后置空
AA *p_external = nullptr; // 指向外部传递的外部对象,不用在析构函数里面管理,
//=================================================================================
public:
Stu() {
name = "s1 ";
age = 1;
// TODO s1是空指针,虽然没有new,但是析构函数可以用delete
std::cout << name << age << " 执行了无参构造函数!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << "空指针没有指向,不能解引用操作" << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
};
Stu(int i, std::string name, AA *p_temp) {
this->name = "s2 ";
age = 2;
d = new int(i);
std::cout << this->name << age << " 执行了有参构造函数!" << std::endl;
std::cout << this->name << age << " 指针指向的地址:" << d << std::endl;
std::cout << this->name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << this->name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
p_internal = new AA(name);
if (p_temp == nullptr) {
p_external = nullptr;
} else {
p_external = p_temp;
p_temp = nullptr; // 这个有必要吗?
}
};
//=================================================================================
Stu(const Stu &s) {
name = "s3 ";
age = 3;
if (s.d == nullptr) {
d = nullptr;
} else {
//开辟新的空间
d = new int(); // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
//把原来的值,拷贝过来。
*d = *s.d; // TODO 注意s不能是空指针,比如s1
}
std::cout << name << age << " 执行了拷贝构造函数(深拷贝)!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
};
//=================================================================================
Stu(Stu &&s) noexcept { // noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。
name = "s4 ";
age = 4; // 移动赋值运算符函数,那这个s.name和s.age怎么处理的啊
if (s.d == nullptr) {
d = nullptr;
} else {
// s的指向的地址赋值给当前对象this
d = s.d;
// s需要置空,断开指向,避免2个指针指向同一块空间
s.d = nullptr;
}
std::cout << name << age << " 执行了移动构造函数!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
};
//=================================================================================
Stu &operator=(const Stu &s) {
name = "s5 ";
age = 5;
if (s.d == nullptr) {
d = nullptr;
} else {
//开辟新的空间
d = new int(); // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
//把原来的值,拷贝过来。
*d = *s.d; // TODO 注意s不能是空指针,比如s1
}
std::cout << name << age << " 执行了拷贝赋值运算符函数!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
return *this;
};
//=================================================================================
Stu &operator=(Stu &&s) noexcept { // noexcept表明函数或操作不会发生异常,会给编译器更大的优化空间。
name = "s6 ";
age = 6; // 移动赋值运算符函数,那这个s.name和s.age怎么处理的啊
if (s.d == nullptr) {
d = nullptr;
} else {
// s的指向的地址赋值给当前对象this
d = s.d;
// s需要置空,断开指向,避免2个指针指向同一块空间
s.d = nullptr;
}
std::cout << name << age << " 执行了移动赋值运算符函数!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
return *this;
};
//=================================================================================
~Stu() {
delete d;
d = nullptr;
std::cout << name << age << " 执行了析构函数!" << std::endl;
delete p_internal;
p_internal = nullptr;
};
//=================================================================================
//=================================================================================
Stu &operator&&(const Stu &s) { // 重新定义了&&运算符(DIY)
name = "s9 ";
age = 9;
if (s.d == nullptr) {
d = nullptr;
} else {
//开辟新的空间
d = new int(); // 不要使用浅拷贝(存在动态成员的隐患),尽量使用深拷贝
//把原来的值,拷贝过来。
*d = *s.d; // TODO 注意s不能是空指针,比如s1
}
std::cout << name << age << " 执行了拷贝赋值运算符函数!" << std::endl;
std::cout << name << age << " 指针指向的地址:" << d << std::endl;
std::cout << name << age << " 指针指向的地址的内容:" << *d << std::endl;
std::cout << name << age << " 指针自身的地址:" << &d << std::endl;
std::cout << "----------------------------------" << std::endl;
return *this;
};
//=================================================================================
};
int main() {
// 类的六个特殊成员函数总结如下:
// 普通构造函数(无参构造函数:Stu(int i)、有参构造函数:Stu(int i)) 析构函数:~Stu()
// 拷贝构造函数:Stu(const Stu &s) 拷贝赋值运算符函数:Stu(Stu &&s)
// 移动构造函数:Stu &operator=(const Stu &s) 移动赋值运算符函数:Stu &operator=(Stu &&s)
//=================================================================================
AA aa("外部对象 ");
//=================================================================================
Stu s1; // 无参构造函数
Stu s2(100, "内部对象 ", &aa); // 有参构造函数
//=================================================================================
Stu s3 = s2; // 拷贝构造函数(深拷贝) // 不能用s1,会有内存问题,看上面;
//=================================================================================
Stu s4;
s4 = s3; // 拷贝赋值运算符函数 // 不能用s1,会有内存问题,看上面;
//=================================================================================
Stu s5 = std::move(s4); // 移动构造函数 // 不能用s1,会有内存问题,看上面;
// TODO s4竟然还可以再用
std::cout << "**************************************** " << s4.d << std::endl; // 0
std::cout << "**************************************** " << s4.name << std::endl; // s4
std::cout << "**************************************** " << s4.age << std::endl; // 4
//=================================================================================
Stu s6;
s6 = std::move(s5); // 移动赋值运算符函数 // 不能用s1,会有内存问题,看上面;
// TODO s5竟然还可以再用
std::cout << "**************************************** " << s5.d << std::endl; // 0
std::cout << "**************************************** " << s5.name << std::endl; // s5
std::cout << "**************************************** " << s5.age << std::endl; // 5
//=================================================================================
Stu s9;
s9 && s6; // 重新定义了&&运算符(DIY)
s9 && s6 && s3 && s2; // 运算符多次重载
// s9 && s6 && s3 && s2 && s1; // s1里面有空指针,不能参与运算符多次重载,因为operator&&函数里面有解引用操作
//=================================================================================
return 0;
}
2.输出结果
/home/liuhao/CLionProjects/Robot_modules_cpp/build/debug/bin/test/class_function
外部对象 123 执行了无参构造函数!
外部对象 123 指针指向的地址:0x1b20c20
外部对象 123 指针指向的地址的内容:456
外部对象 123 指针自身的地址:0x7fff41aa8aa8
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7fff41aa8ad8
----------------------------------
s2 2 执行了有参构造函数!
s2 2 指针指向的地址:0x1b21050
s2 2 指针指向的地址的内容:100
s2 2 指针自身的地址:0x7fff41aa8b18
----------------------------------
内部对象 123 执行了无参构造函数!
内部对象 123 指针指向的地址:0x1b210b0
内部对象 123 指针指向的地址的内容:456
内部对象 123 指针自身的地址:0x1b21098
----------------------------------
s3 3 执行了拷贝构造函数(深拷贝)!
s3 3 指针指向的地址:0x1b210d0
s3 3 指针指向的地址的内容:100
s3 3 指针自身的地址:0x7fff41aa8b58
----------------------------------
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7fff41aa8b98
----------------------------------
s5 5 执行了拷贝赋值运算符函数!
s5 5 指针指向的地址:0x1b210f0
s5 5 指针指向的地址的内容:100
s5 5 指针自身的地址:0x7fff41aa8b98
----------------------------------
s4 4 执行了移动构造函数!
s4 4 指针指向的地址:0x1b210f0
s4 4 指针指向的地址的内容:100
s4 4 指针自身的地址:0x7fff41aa8bd8
----------------------------------
**************************************** 0
**************************************** s5
**************************************** 5
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7fff41aa8c18
----------------------------------
s6 6 执行了移动赋值运算符函数!
s6 6 指针指向的地址:0x1b210f0
s6 6 指针指向的地址的内容:100
s6 6 指针自身的地址:0x7fff41aa8c18
----------------------------------
**************************************** 0
**************************************** s4
**************************************** 4
s1 1 执行了无参构造函数!
s1 1 指针指向的地址:0
s1 1 指针指向的地址的内容:空指针没有指向,不能解引用操作
s1 1 指针自身的地址:0x7fff41aa8c58
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1b21110
s9 9 指针指向的地址的内容:100
s9 9 指针自身的地址:0x7fff41aa8c58
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1b21130
s9 9 指针指向的地址的内容:100
s9 9 指针自身的地址:0x7fff41aa8c58
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1b21150
s9 9 指针指向的地址的内容:100
s9 9 指针自身的地址:0x7fff41aa8c58
----------------------------------
s9 9 执行了拷贝赋值运算符函数!
s9 9 指针指向的地址:0x1b21170
s9 9 指针指向的地址的内容:100
s9 9 指针自身的地址:0x7fff41aa8c58
----------------------------------
s9 9 执行了析构函数!
s6 6 执行了析构函数!
s4 4 执行了析构函数!
s5 5 执行了析构函数!
s3 3 执行了析构函数!
s2 2 执行了析构函数!
内部对象 123 执行了析构函数!
s1 1 执行了析构函数!
外部对象 123 执行了析构函数!
Process finished with exit code 0
来源:CSDN
作者:魔方研究生
链接:https://blog.csdn.net/liuhaobjtu/article/details/104542699