20210705cpp学习

Jul 6, 2021

C++

纯虚继承多态的问题

创建 worker.h

1
2
3
4
5
6
7
8
9
10
11
12
#pragma once
#include <iostream>
#include <string>
using namespace std;

class Worker {
public:
virtual void showInfo() = 0;
virtual string getDeptName() = 0;
int m_Id, m_DeptId;
string m_Name;
};

创建普通员工类Employee.h 和.cpp 其继承于Worker

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Employee.h
#pragma once
#include <iostream>
using namespace std;
#include "worker.h"
class Employee: public Worker {
public:
Employee(int id, string name, int dId);
virtual void showInfo();
virtual string getDeptName();
};
// Employee.cpp
#include "Employee.h"
Employee::Employee(int id, string name, int dId) {
this->m_Id = id;
this->m_Name = name;
this->m_DeptId = dId;
}
void Employee::showInfo() {
return "我是要展示的info";
}
string Employee::getDeptName() {
return "职工";
}

此时运行使用多态方案,比如其他继承Worker 的类也想使用同样方法,然后delete 会出现内存泄漏bug:

1
2
3
4
5
6
int main() {
Worker *worker = NULL;
worker = new Employee(1, "aker", 1);
worker.showInfo();
delete worker; // 这里就会报内存泄漏
}

为什么?生成Employee地址空间,delete 自己的空间怎么会报错?

我们这样理解: Worker *worker,worker 是纯虚指针,指向纯虚单独保存的空间,这里只有Worker。delete worker,虽然是打算释放Employee,但是纯虚里面不包括Employee 其他数据指针。直接delete 就会造成无法释放余下那部分数据。

解决方法有两种参考:

  1. 自己实现虚析构:
1
2
3
4
class Employee: public Worker {
public:
virtual ~Employee() {};
}

这样释放就能直接找到自己的析构。

  1. 提供自己的delete 方法,自己释放自己:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Worker {
virtual void release() {
delete this;
};
};
class Employee: public Worker {
public:
virtual void release();
};
void Employee::release() {
delete this;
}

// 使用
worker.release();

cpp引用注意点

1
2
3
4
5
6
7
8
9
10
11
12
13
// 相当于将aa指针也指向了a 的地址: &a
void func1(int * const aa) {
cout << "result: " << *aa << endl;
}
// cpp 的引用
void func2(int &aa) {
cout << "result: " << aa << endl;
}
void test() {
int a = 100;
func1(&a);
func2(a);
}

cpp深拷贝/浅拷贝

浅拷贝: 简单的赋值拷贝操作
深拷贝: 在堆区重新申请空间,进行拷贝操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Person {
public:
Person() {}
Person(const Person &p) {
cout << "拷贝构造函数!" << endl;
m_age = p.m_age;
m_height = new int(*p.m_height);
}
public:
int m_age;
int *m_height;
};

void test() {
Person p1;
Person p2(p1);
}

如果不实现 Person(const Person &p)那么就是浅拷贝,直接进行对象的赋值操作; 但是如果内部属性在堆区开辟,一定要提供拷贝构造函数,否则可能导致浅拷贝的重复释放堆区的问题(赋值了指针,p2->m_height 有两份指针,释放时就释放了两次!)!