《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; // zhangsan
cout << "s2:" << s2.c_str() << endl; // zhangsan
s2.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;
}更多推荐



所有评论(0)