day3: 对象的构造与析构, 构造函数的分类与调用, 拷贝构造函数的调用时机, 构造函数的调用规则, 深拷贝和浅拷贝, 多个对象的构造和析构(初始化列表, 类对象作为成员), explicit 关键字(禁止隐式转换), 动态创建对象(malloc/realloc/calloc 在堆中创建空间, new 关键字), 扩展 new 和 delete

This commit is contained in:
flykhan 2023-07-26 18:10:36 +08:00
parent 220ea31d68
commit 3320bf12d2
18 changed files with 808 additions and 0 deletions

View File

@ -5,3 +5,5 @@
#### day1: C++简介, ::作用域, namespace 命名空间, using 声明, using 编译指令, 类型转换, struct 类型加强, bool 关键字, 三目运算符增强, const 增强 #### day1: C++简介, ::作用域, namespace 命名空间, using 声明, using 编译指令, 类型转换, struct 类型加强, bool 关键字, 三目运算符增强, const 增强
#### day2: const 和#define 的区别, 引用(reference) 【重要】, 内联函数, 函数的默认值参数, 函数的占位参数, 函数重载和 extern "c", 类与对象的概念, 面向对象程序设计案例 #### day2: const 和#define 的区别, 引用(reference) 【重要】, 内联函数, 函数的默认值参数, 函数的占位参数, 函数重载和 extern "c", 类与对象的概念, 面向对象程序设计案例
#### day3: 对象的构造与析构, 构造函数的分类与调用, 拷贝构造函数的调用时机, 构造函数的调用规则, 深拷贝和浅拷贝, 多个对象的构造和析构(初始化列表, 类对象作为成员), explicit 关键字(禁止隐式转换), 动态创建对象(malloc/realloc/calloc 在堆中创建空间, new 关键字), 扩展 new 和 delete,

74
day3/d1.cpp Normal file
View File

@ -0,0 +1,74 @@
// 对象的构造与析构
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Animal
{
public:
Animal();
Animal(const char *name, const char *food);
~Animal(); // 析构函数(对象回收时,清理资源)
public:
void eat();
void say(const char *msg);
private:
char *name, *food;
};
Animal::Animal()
{
name = (char *)malloc(32);
food = (char *)malloc(32);
strcpy(name, "小动物");
strcpy(food, "");
}
Animal::Animal(const char *name, const char *food)
{
this->name = (char *)malloc(32);
this->food = (char *)malloc(32);
strcpy(this->name, name);
strcpy(this->food, food);
}
Animal::~Animal()
{
cout << name << "空间回收" << endl;
// 回收在构造函数(初始化)中动态分配的空间
free(name);
free(food);
}
void Animal::eat()
{
cout << name << "吃: " << food << endl;
}
void Animal::say(const char *msg)
{
cout << name << "遇到主人: " << msg << endl;
}
int main()
{
// 尽量使用堆空间创建类的对象: 使用 类指针 和 new 关键字
Animal *anm1 = new Animal();
anm1->eat();
// 使用栈空间的情况
Animal anm2;
anm2.say("小浣熊");
// 使用括号
Animal anm3("小黄", "");
anm3.eat();
anm3.say("旺旺...");
return 0;
}

60
day3/d10.cpp Normal file
View File

@ -0,0 +1,60 @@
// 深拷贝和浅拷贝
// 深拷贝举例
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Person
{
private:
char *name;
int age;
public:
Person(const char *name, int age)
{
this->name = (char *)malloc(32);
strcpy(this->name, name);
this->age = age;
}
Person(const Person &obj) // 深拷贝,重写构造方法
{
this->name = (char *)malloc(32);
strcpy(this->name, obj.name);
this->age = obj.age;
}
~Person()
{
if (name != NULL)
{
free(name);
}
}
public:
void setName(char *name)
{
strcpy(this->name, name);
}
void show()
{
cout << this << " " << name << ", " << age << endl;
}
};
int main()
{
Person p1("disen", 20);
Person p2 = p1;
p2.setName("lucy");
Person p3 = Person(p2);
p3.setName("Jack");
p1.show();
p2.show();
p3.show();
return 0;
}

27
day3/d11.cpp Normal file
View File

@ -0,0 +1,27 @@
// 多个对象的构造和析构
// 初始化列表
#include <iostream>
using namespace std;
class A
{
private:
int x, y, z;
// char *name;
string name; // char * 建议替换为 string
public:
A(int x, int y, int z, const string &name) : x(x), y(y), z(z), name(name) {}
void show()
{
cout << x << ", " << y << ", " << z << ", " << name << endl;
}
};
int main()
{
A a1(10, 20, 4, "disen");
a1.show();
return 0;
}

48
day3/d12.cpp Normal file
View File

@ -0,0 +1,48 @@
// 多个对象的构造和析构
// 类对象作为成员
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A()" << endl;
}
A(int x)
{
cout << "A(int x)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
};
class B
{
public:
B() // 构造函数用于初始化成员数据,说明成员变量先创建
{
cout << "B()" << endl;
}
B(int x)
{
cout << "B(int x)" << endl;
}
~B() // A 的对象在 B 的空间中A 对象在 B 空间释放之后就失效,失效也会释放空间(调用析构函数)
{
cout << "~B()" << endl;
}
private:
A a; // A 类的对象作为 B 类的成员
};
int main()
{
B b1;
return 0;
}

50
day3/d13.cpp Normal file
View File

@ -0,0 +1,50 @@
// 多个对象的构造和析构
// 类对象作为成员
// d12 的改造测试
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "A()" << endl;
}
A(int x)
{
cout << "A(int x)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
};
class B
{
public:
B() // 构造函数用于初始化成员数据,说明成员变量先创建
{
cout << "B()" << endl;
}
// 成员名:(参数名)
B(int x) : a(x) // 指定 a 对象的构造函数进行数据初始化
{
cout << "B(int x)" << endl;
}
~B() // A 的对象在 B 的空间中A 对象在 B 空间释放之后就失效,失效也会释放空间(调用析构函数)
{
cout << "~B()" << endl;
}
private:
A a; // A 类的对象作为 B 类的成员
};
int main()
{
B b1(1);
return 0;
}

43
day3/d14.cpp Normal file
View File

@ -0,0 +1,43 @@
// explicit 关键字(禁止隐式转换)
#include <iostream>
using namespace std;
class Person
{
private:
int age;
string name;
public:
Person(const char *name, int age = 18)
{
this->name = name;
this->age = age;
}
// explicit 使得不存在从 "int" 转换到 "Person" 的适当构造函数
explicit Person(int age) // 进制 Person p = 值
{
this->age = age;
this->name = "disen";
}
public:
void show()
{
cout << name << ", " << age << endl;
}
};
int main()
{
Person p1 = "jack";
Person p2 = Person("doken", 9);
Person p3 = Person(1);
// Person p4 = 2; // 不存在从 "int" 转换到 "Person" 的适当构造函数
p1.show();
p2.show();
p3.show();
return 0;
}

51
day3/d15.cpp Normal file
View File

@ -0,0 +1,51 @@
// 动态创建对象(malloc / realloc / calloc 在堆中创建空间, new 关键字)
#include <iostream>
#include <cstdlib>
using namespace std;
class A
{
private:
int x;
public:
A(int x)
{
this->x = x;
cout << "A(int)" << endl;
}
~A()
{
cout << "~A()" << endl;
}
public:
void init(int x)
{
this->x = x;
cout << "init(int)" << endl;
}
void clean()
{
cout << "clean()" << endl;
}
};
int main()
{
// 1) 使用 malloc 方式创建
// cout << "A size is " << sizeof(A) << endl;
// A *a1 = (A *)malloc(sizeof(A));
// // a1->A(20); // 不允许显式调用构造函数
// a1->init(20); // 初始化数据
// a1->clean(); // 释放数据的空间
// a1->~A(); // 析构函数可以显式调用
// free(a1);
// 2) new 方式创建delete释放
A *a1 = new A(1);
delete a1; // 用完之后直接 delete 释放空间
return 0;
}

23
day3/d16.cpp Normal file
View File

@ -0,0 +1,23 @@
// 扩展 new 和 delete
// 数组的 new 和 delete
#include <iostream>
using namespace std;
int main()
{
// 使用拓展的 new 创建类对象数组
int *p = new int[6]{1, 2, 3, 4, 5, 6};
for (int i = 0; i < 10; i++)
{
cout << *(p + i) << endl;
}
delete[] p; // 释放数组空间
cout << "--------------------" << endl;
for (int i = 0; i < 10; i++)
{
cout << *(p + i) << endl;
}
return 0;
}

43
day3/d17.cpp Normal file
View File

@ -0,0 +1,43 @@
#include <iostream>
#include <cstdlib>
using namespace std;
class A
{
private:
string name;
public:
A()
{
cout << "A()" << endl;
name = "no name";
}
A(const string &name)
{
cout << "A(const string &name)" << endl;
this->name = name;
cout << "name: " << name << endl;
}
~A()
{
cout << name << "~A()" << endl;
}
};
int main()
{
// A *p = new A[5];
// delete[] p;
// A *p2 = new A[4]{A("a"), A("b"), A("c"), A("d")};
// delete[] p2; // 释放数组中成员对象时,从高(地址)到低(地址)依次释放
A *a = new A("abc");
free(a); // 只是放指针指向的堆空间,不会调用对象的析构函数
char *a2 = (char *)malloc(sizeof(A));
delete a2; // 可以删除简单的 void* 指针
return 0;
}

35
day3/d2.cpp Normal file
View File

@ -0,0 +1,35 @@
// 构造函数的分类与调用
// 拷贝构造函数
#include <iostream>
using namespace std;
class A
{
public:
int x;
public:
A() {}
A(A &other) // 拷贝构造函数
{
this->x = other.x;
}
};
int main()
{
A a1; // 调用无参的构造函数进行初始化 a1 对象
a1.x = 10;
cout << "a1 x = " << a1.x << endl;
A a2(a1); // 使用拷贝构造
cout << "a2 x = " << a2.x << endl;
A *a3 = new A(); // 使用指针和new在堆空间创建对象
// a3->x = 20;
cout << "a3 x = " << a3->x << endl;
return 0;
}

44
day3/d3.cpp Normal file
View File

@ -0,0 +1,44 @@
// 构造函数的分类与调用
#include <iostream>
using namespace std;
class B
{
private:
int n;
public:
// B() { cout << "B()" << endl; }
B(int n)
{
cout << "B(int n)" << endl;
this->n = n;
}
B(const B &other)
{
cout << "B(B &other)" << endl;
this->n = other.n;
}
public:
void showN()
{
cout << "n = " << n << endl;
}
};
int main()
{
B b1 = 20; // 隐式调用 B(int n), B(20), 只创建一个对象
B b2 = B(30); // 显式调用 B(int n)
B b3 = b2; // 隐式调用 B(B &other)
B &b4 = b3; // 不会创建空间,只是一个别名
B b5(b4); // 显式调用 B(B &other)
return 0;
}

56
day3/d4.cpp Normal file
View File

@ -0,0 +1,56 @@
// 构造函数的分类与调用
#include <iostream>
#include <bitset>
using namespace std;
class C
{
private:
int x, y;
public:
C(int x)
{
this->x = x;
}
C(int x, int y)
{
this->x = x;
this->y = y;
}
C(const C &other)
{
this->x = other.x;
this->y = other.y;
}
void show()
{
cout << "x = " << x << ", y = " << y << endl;
}
~C()
{
cout << this << "释放资源" << endl;
}
};
int main()
{
cout << "C(0,1) 之前" << endl;
C(0, 1); // 匿名创建的类对象,创建完后就直接释放了
cout << "C(0,1) 之后" << endl;
C c1(1, 2);
c1.show();
C c2 = (1, 5); // 使用单参数构造函数 C(int x), 然后将其改为 ", 运算" 后面的值
// C c2 = 1;
c2.show();
C c3 = C(3, 4);
c3.show();
C c4(c3);
c4.show();
C &c5 = c4;
c5.show();
return 0;
}

54
day3/d5.cpp Normal file
View File

@ -0,0 +1,54 @@
// 创建类对象的指针
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class A
{
public:
char *msg;
public:
A()
{
this->msg = (char *)malloc(30);
strcpy(this->msg, "haha");
}
A(const char *msg)
{
this->msg = (char *)malloc(30);
strcpy(this->msg, msg);
}
~A()
{
cout << this << "release msg : " << this->msg << endl;
free(this->msg);
// free(this);
}
};
int main()
{
A *a1 = new A;
cout << "a1->msg: " << a1->msg << endl;
A *a2 = new A("disen 666");
cout << "a2->msg: " << a2->msg << endl;
// 【注意】指针释放空间时, 不会自动执行对象的析构函数
// 可以通过手动调用 对象的析构方法 或使用 delete
a1->~A();
free(a1);
// a2->~A();
// delete a1;
delete a2;
A a3;
// 注意: delete 只能删除 new 出来的对象,即对象的指针
// A &a4 = a3;
// delete &a4;
return 0;
}

57
day3/d6.cpp Normal file
View File

@ -0,0 +1,57 @@
// 拷贝构造函数的调用时机
// 编译器优化,不会调用拷贝构造函数,而是直接创建一个返回值的引用
#include <iostream>
using namespace std;
class A
{
public:
int x = 0;
public:
A()
{
cout << this << " A()" << endl;
}
A(const A &other)
{
this->x = other.x;
cout << this << " A(const A &other)" << endl;
}
~A()
{
cout << this << " ~A()" << endl;
}
};
void test1(A a) // ?是否调用拷贝构造函数
{
cout << "test1(A a) a.x = " << a.x << endl;
// 当函数结束时a 释放,会调用析构函数
}
A test2()
{
A a1; // 局部的类对象, 没有执行拷贝构造函数
a1.x = 1;
cout << "test2() a1.x = " << a1.x << endl;
return a1; // 释放局部对象 a1
}
void test3()
{
A a2 = test2(); // 返回 A 类的对象,没有调用拷贝构造函数,只是创建了一个 test2() 返回值的引用
cout << "test3() a2.x = " << a2.x << endl;
}
int main()
{
A a0;
// test1(a0); // 作为值传递,调用拷贝构造函数
test3();
cout << "over" << endl;
return 0;
}

60
day3/d7.cpp Normal file
View File

@ -0,0 +1,60 @@
// 拷贝构造函数的调用时机
// 编译器优化,不会调用拷贝构造函数,而是直接创建一个返回值的引用
#include <iostream>
using namespace std;
class A
{
public:
int x = 0;
public:
A()
{
cout << this << " A()" << endl;
}
A(const A &other)
{
this->x = other.x;
cout << this << " A(const A &other)" << endl;
}
~A()
{
cout << this << " ~A()" << endl;
}
};
void test1(A &a) // ?是否调用拷贝构造函数
// void test1(A a) // ?是否调用拷贝构造函数
{
cout << "test1(A a) a.x = " << a.x << endl;
// 当函数结束时a 释放,会调用析构函数
}
A test2() // 不要声明为 A &test2(), 因为返回对象时,会释放局部对象,导致返回的引用指向一个已经释放的对象
{
A a1; // 局部的类对象, 没有执行拷贝构造函数
a1.x = 1;
cout << "test2() a1.x = " << a1.x << endl;
return a1; // 释放局部对象 a1
}
void test3()
{
cout << "tsss = " << endl;
A a2 = test2(); // 返回 A 类的对象,没有调用拷贝构造函数,只是创建了一个 test2() 返回值的引用
cout << "test3() a2.x = " << a2.x << endl;
}
int main()
{
A a0;
test1(a0); // 作为值传递,调用拷贝构造函数
// test3();
cout << "over" << endl;
return 0;
}

30
day3/d8.cpp Normal file
View File

@ -0,0 +1,30 @@
// 构造函数的调用规则
#include <iostream>
using namespace std;
class A
{
public:
int x, y;
void show()
{
cout << this << " x = " << x << ", y = " << y << endl;
}
};
int main()
{
A a1;
// A a2 = a1; // 自动调用拷贝构造函数 A(const A&obj)
a1.x = 20;
A a2 = a1; // 自动调用拷贝构造函数 A(const A&obj)
a1.y = 30;
// A a2 = a1; // 自动调用拷贝构造函数 A(const A&obj)
a1.show(); // 20,30 浅拷贝
a2.show(); //
return 0;
}

51
day3/d9.cpp Normal file
View File

@ -0,0 +1,51 @@
// 深拷贝和浅拷贝
// 浅拷贝举例
#include <iostream>
#include <cstdlib>
#include <cstring>
using namespace std;
class Person
{
private:
char *name;
int age;
public:
Person(const char *name, int age)
{
this->name = (char *)malloc(32);
this->age = age;
}
void release_name_pointer()
{
free(name);
}
public:
void setName(char *name)
{
strcpy(this->name, name);
}
void show()
{
cout << name << ", " << age << endl;
}
};
int main()
{
Person p1("disen", 20);
Person p2 = p1;
Person p3 = Person(p2);
p3.setName("Jack");
p1.show();
p2.show();
p3.show();
// p1.release_name_pointer();
p2.release_name_pointer();
return 0;
}