《C++程序设计》笔记p3
C++对象的生命周期
- 为对象创建内存
- 创建对象的各个成员变量(调用各个成员变量的构造函数)
- 调用构造函数初始化对象自身
- 使用对象...
- 调用析构函数释放对象使用的资源。
- 销毁各个程序员变量(调用各个成员变量的析构函数)
- 释放内存
析构函数 (Destructor)
作用:释放对象对象使用的资源。
析构函数 会在对象销毁前自动调用。如果类内没有定义析构函数,则编译器也会为其添加一个析构函数,默认的析构函数什么都不做。
析构函数的语法
class 类名{public:~类名(void) {... 做释放内存或关闭文件等操作。}
}
说明:
- 析构函数只有一个,且不能重载。
- 析构函数没有参数和返回值。
- 析构函数会在对象销毁前自动调用。无需手动调用。
全局变量(对象)的构造和析构函数调用规则
全局变量(对象)存在于数据段,而数据段是在 main 函数调用之前创建,并创建数据段内的对象,因此全局变量(对象)的构造函数会先用main调用。同样析构函数也会在 main 函数结束后调用。
构造函数的传参语法
类名 对象名; // 调用无参的构造函数
类名 对象名(实参列表); // 调用有参的构造函数,根据重载规则匹配构造函数
类名 对象名 = 值; // 调用一个参数的构造函数(同时根据重载匹配规则)
如
int i = 0; //等同于 int i(0);
示例代码
#include <iostream>
#include <stdlib.h>
#include <string.h>using namespace std;// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {public:// 将字符串初始化成 n个内容为 c的字符MyString(char c, int n) {cout << "MyString(" << c << "," << n<<")\n";data = (char*)malloc(n+1);for (int i = 0; i < n; i++) {data[i] = c;}data[n] = '\0';}MyString(const char * p=""):data(NULL) {cout << "MyString(" << p << ")\n";// 计算传入参数的长度int str_len = strlen(p);data = (char*)malloc(str_len+1);strcpy(data, p);}// 析构函数~MyString(){cout << "~MyString(" << data << ")" << endl;free(data);}private:char * data;
};int main(int argc, char * argv[]) {MyString s1; // 调用无参数的构造函数MyString s2('x', 10); // 根据重载规则调用两个参数的构造函数。MyString s3("name1"); // 调用一个参数的构造函数MyString s4 = "name2"; // 调用一个参数的构造函数cout << sizeof(s1) << endl;cout << "程序结束!" << endl;return 0;
}// MyString x1("world");
// MyString x2("1111");
new
和 delete
关键字
作用:在堆上创建对象和释放对象 。
C 语言分配内存的方法: malloc/free
C++ 创建对象的方法: new
/ delete
- new 分配内存,同时调用构造函数
- delete 调用析构函数,然后释放内存
语法
// 创建单个对象
new 类名; // 调用无参数的构造函数
new 类名(实参列表); // 根据重载规则调用有参数的构造函数// 创建对象数组
new 类名[对象个数(整数)]
// 创建对象数组,并指定构造函数
new 类名[对象个数(整数)]{每个对象的初始化构造函数}// 销毁单个对象
delete 对象地址
// 销毁对象数组
delete [] 对象地址
深拷贝和浅拷贝
浅拷贝:是指在复制对象的过程中,对象的每个成员都依次赋值给新对象的成员各个成员。
对象的默认复制是浅拷贝
深拷贝:是指在复制对象的过程中,每个对象的资源都各自独立,不共用,成为独立的个体。
拷贝构造函数(copy construtor)
作用:是进行深拷贝
语法格式
class 类名{类名(const 类名 & src){}
};
说明:
- 拷贝构造数是C类的缺省构造函数。如果不写此构造函数。C 默认生成一个缺省的构造函数。默认执行浅拷贝
示例代码
#include <stdlib.h>
#include <string.h>using namespace std;// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {public:// 将字符串初始化成 n个内容为 c的字符MyString(char c, int n) {cout << "MyString(" << c << "," << n<<")\n";data = (char*)malloc(n+1);for (int i = 0; i < n; i++) {data[i] = c;}data[n] = '\0';}MyString(const char * p=""):data(NULL) {cout << "MyString(" << p << ")\n";// 计算传入参数的长度int str_len = strlen(p);data = (char*)malloc(str_len+1);strcpy(data, p);}// 拷贝构造函数,对指针执向的内容进行深度复制MyString(const MyString & src) {cout << "MyString(const MyString& src.data:" << src.data << ")\n";// 求源对象字符的长度int str_len = strlen(src.data);data = (char*) malloc(str_len+1);strcpy(data, src.data);}// 析构函数~MyString(){cout << "~MyString(" << data << ")" << endl;free(data);}const char * c_str(void) {return data;}private:char * data;
};int main(int argc, char * argv[]) {MyString s1 = "zhangsan";MyString s2 = s1; // 调用拷贝构造函数MyString s3(s2); // 调用拷贝构造函数cout << "s1:" << s1.c_str() << endl;cout << "s2:" << s2.c_str() << endl;cout << "程序结束!" << endl;return 0;
}
示例:
给MyString添加两个成员函数
class MyString{public:void copy(const char * content) {...}void copy(const MyString & src) {...}
};
使其修改 data 执行的内容,让器变为新的内容
参考
#include <iostream>
#include <stdlib.h>
#include <string.h>using namespace std;// 定义一个MyString类,使用动态数组来存储字符信息
class MyString {public:// 将字符串初始化成 n个内容为 c的字符MyString(char c, int n) {cout << "MyString(" << c << "," << n<<")\n";data = (char*)malloc(n+1);for (int i = 0; i < n; i++) {data[i] = c;}data[n] = '\0';}MyString(const char * p=""):data(NULL) {cout << "MyString(" << p << ")\n";// 计算传入参数的长度int str_len = strlen(p);data = (char*)malloc(str_len+1);strcpy(data, p);}// 拷贝构造函数,对指针执向的内容进行深度复制MyString(const MyString & src) {cout << "MyString(const MyString& src.data:" << src.data << ")\n";// 求源对象字符的长度int str_len = strlen(src.data);data = (char*) malloc(str_len+1);strcpy(data, src.data);}// 析构函数~MyString(){cout << "~MyString(" << data << ")" << endl;free(data);}const char * c_str(void) {return data;}private:char * data;public:// 要求不能有内存泄漏void copy(const char * content) {// 释放自己原有的内存free(data);int str_len = strlen(content);data = (char*)malloc(str_len+1);strcpy(data, content);}void copy(const MyString & src){// 释放自己原有的内存free(data);int str_len = strlen(src.data);data = (char*)malloc(str_len+1);strcpy(data, src.data);}
};int main(int argc, char * argv[]) {MyString s1 = "zhangsan";MyString s2;s2.copy(s1);cout << "s1:" << s1.c_str() << endl; // zhangsancout << "s2:" << s2.c_str() << endl; // zhangsans2.copy("lisi");cout << "s2:" << s2.c_str() << endl; // lisi cout << "程序结束!" << endl;return 0;
}
C++ 成员函数的调用方式:
语法
对象.函数名(参数列表) 对象指针->函数名(参数列表)
面向对象编程(OOP)
OOP(Object Oriented Programming)
类:对象的描述(蓝图)
对象:类创建的实例,真正占用内存的变量。
思想:用类来描述对象的行为。用类封装对象数据。
描述方法:
有两个人(Human),张三(zhang3) 和 李四(li3)张三工作赚钱 1000 元
李四借张三 300 元
李四买游戏机花了270元;
张三教李四玩王者荣耀
李四教张三 C++用面相对象的思想来描述。
示例代码:
#include <iostream>
#include <stdlib.h>
#include <string.h>using namespace std;class Human {public:Human(const char * n) : name(n),money(0){}void showInfo(void) {cout << name << ", 有钱:" << money << "元, 技能:" << skill << endl;}void work(int m) {money += m;cout << name << " 工作赚了" << m << "元,共有" << money << "元" << endl;}void borrowFrom(Human & h, int m) {if (m > h.money) {cout << h.name << "没有" << m << "元这么多钱,借钱失败!" << endl;return;}h.money -= m;money += m;cout << h.name << "借给" << name << m << "元钱!" << endl;}private:string name;int money;string skill; // 技能 :w};int main(int argc, char * argv[]) {// 有两个人(Human),张三(zhang3) 和 李四(li3)Human zhang3("张三");Human li4("李四");// 张三工作赚钱 1000 元// zhang3.work(1000);// 李四借张三 300 元li4.borrowFrom(zhang3, 300);zhang3.showInfo();li4.showInfo();
// // 李四买游戏机花了270元;
// li4.buy("游戏机", 270);
// // 李四教张三玩王者荣耀
// li4.teach(zhang3, "王者荣耀");
// // 张三教李四 C++
// zhang3.teach(li4, "C++");cout << "程序结束!" << endl;return 0;
}