C++基础笔记

静态变量

所有对象都共享同一份数据

编译阶段分配内存

类内声明类外初始化

1
2
3
4
5
6
7
8
9
10
11
class P{
public:
static int m_A; // 类内声明
}
int P::m_A = 100; // 类外初始化

int main(){
P p1;
cout << p1.m_A; // 对象访问
cout << P::m_A; // 类名访问
}

常函数

常函数只能修改mutable修饰的成员变量

常对象只能调用常函数,常对象只能修改mutable修饰的成员变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class C{
public:
int m_A;
mutable int m_B; // mutable修饰的成员变量可在常函数内修改
void test() const{ // 常函数,此处const修饰this指针
this->m_A = 100; // 报错,常函数无法修改成员变量
this->m_B = 100; // 可修改
}
// 普通函数
void func(){}
}

void test2(){
const C c; // 常对象
c.m_A = 100; // 报错,常对象无法修改成员变量
c.m_B = 100; // 可修改
c.test();
c.func(); // 报错,常对象只能调用常函数
}

运算符重载

左移运算符

1
2
3
4
5
6
7
8
9
10
class Person{
public:
int m_Age;
}
// 只能在全局函数中重载,成员函数不行,无法实现cout<<的效果
ostream& operator<<(ostream& cout, Person& p){
cout << "p.m_Age" << p.m_Age << endl;
return cout; // 链式
}

递增运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyInteger {
public:
int m_num;

// 前置
MyInteger &operator++() {
m_num++;
return *this;
}

// 后置,函数带有int占位参数
MyInteger operator++(int) {
MyInteger tmp = *this;
m_num++;
return tmp;
}
};

函数调用运算符重载

1
2
3
4
5
6
7
8
9
10
11
class Call {
// 函数调用-> ()运算符重载
void operator()() {
cout << "__call__" << endl;
}
}

void test_call(){
MyInteger i{};
i(); // 调用
}

继承

继承构造析构顺序:

​ 构造:先父后子

​ 析构:先子后父

菱形继承问题,会继承多份顶层基类的数据,浪费资源,使用虚继承优化,利用虚基类指针维护虚基类表中一份数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "iostream"

using namespace std;

// 菱形继承
void extend() {
class Parent {
public:
int m_Age;
};

class Father : public Parent {
};

class Mama : public Parent {
};
class Son : public Father, public Mama {
public:
int m_Age;
};
Son son;
son.Father::m_Age = 30;
son.Mama::m_Age = 20;
cout << son.Father::m_Age << endl; // 30
cout << son.Mama::m_Age << endl; // 20
// 菱形继承,同一份数据在子类中存储多次,资源浪费
}

// 虚继承
void virtual_extend() {
// 虚基类
class Parent {
public:
int m_Age;
};

// virtual 关键字
class Father : virtual public Parent {
};

class Mama : virtual public Parent {
};

class Son : public Father, public Mama {
public:
int m_Age;
};
Son son;
son.Father::m_Age = 30;
son.Mama::m_Age = 20;
cout << son.Father::m_Age << endl; // 20
cout << son.Mama::m_Age << endl; // 20
// 虚继承保证数据只继承一份,使用虚基类指针(vbptr)指向虚基类表(vbtable)
}

int main() {
cout << "菱形继承" << endl;
extend();
cout << "虚继承" << endl;
virtual_extend();
return 0;
}

多态

虚继承

解决菱形继承,同一份数据在子类中存储多次,资源浪费问题

虚继承保证数据只继承一份,使用虚基类指针(vbptr)指向虚基类表(vbtable),继承的是指针而不是值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
#include "iostream"

using namespace std;

// 菱形继承
void extend() {
class Parent {
public:
int m_Age;
};

class Father : public Parent {
};

class Mama : public Parent {
};
class Son : public Father, public Mama {
public:
int m_Age;
};
Son son;
son.Father::m_Age = 30;
son.Mama::m_Age = 20;
cout << son.Father::m_Age << endl; // 30
cout << son.Mama::m_Age << endl; // 20
// 菱形继承,同一份数据在子类中存储多次,资源浪费
}

// 虚继承
void virtual_extend() {
// 虚基类
class Parent {
public:
int m_Age;
};

// virtual 关键字
class Father : virtual public Parent {
};

class Mama : virtual public Parent {
};

class Son : public Father, public Mama {
public:
int m_Age;
};
Son son;
son.Father::m_Age = 30;
son.Mama::m_Age = 20;
cout << son.Father::m_Age << endl; // 20
cout << son.Mama::m_Age << endl; // 20
// 虚继承保证数据只继承一份,使用虚基类指针(vbptr)指向虚基类表(vbtable)
}

int main() {
cout << "菱形继承" << endl;
extend();
cout << "虚继承" << endl;
virtual_extend();
return 0;
}

虚析构

多态时,采用父类指针指向子类对象时,释放父类指针不会调用子类析构函数,若子类中存在堆区数据,会存在内存泄漏。使用虚析构解决此类问题。

含纯虚析构的类为抽象类,纯虚析构需要在类外实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#include <iostream>

using namespace std;


void not_virtual() {
class Animal {
public:
~Animal() {
cout << "~Animal()" << endl;
}
};

class Dog : public Animal {
public:
string *m_name;

Dog(string name) {
m_name = new string(name);
cout << "Dog()" << endl;
}

~Dog() {
if (m_name) {
delete m_name;
m_name = nullptr;
}
cout << "~Dog()" << endl;
}
};

Animal *animal = new Dog("wangcai");
delete animal;
}


void virtual_destruct() {
class Animal {
public:
virtual ~Animal() {
cout << "~Animal()" << endl;
}
};

class Dog : public Animal {
public:
string *m_name;

Dog(string name) {
m_name = new string(name);
cout << "Dog()" << endl;
}

~Dog() {
if (m_name) {
delete m_name;
m_name = nullptr;
}
cout << "~Dog()" << endl;
}
};


Animal *animal = new Dog("wangcai");
delete animal;
}

class Test {
// 纯虚析构函数,不能被实例化
// 需要实现
virtual ~Test() = 0;
};
// 纯虚析构实现
Test::~Test() {
cout << "~Test()" << endl;
}

int main() {
// 调用了Dog构造函数, Animal析构函数
// 但是没有调用Dog析构函数,导致Dog中的m_name没有释放
not_virtual();
// 调用了Dog构造函数和虚构函数, Animal析构函数
// 使用了虚析构函数,Dog中的m_name被释放了
virtual_destruct();
return 0;
}

C++基础笔记
http://blog.rainna.xyz/2022/04/17/2022-04-17-C++基础笔记/
作者
rainnalv
发布于
2022年4月17日
许可协议