Skip to content

Commit 842876f

Browse files
committed
update pics
1 parent 8f93a73 commit 842876f

12 files changed

+653
-30
lines changed

.DS_Store

0 Bytes
Binary file not shown.

C++入门/1.C++基础.md

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,28 @@ cout << sqrt(25.0);
390390
通用的规则是,如果函数返回在函数中创建的临时对象,则不要使用引用。
391391
如果函数返回的是通过引用或指针传递给它的对象,则应按引用返回对象。
392392

393+
##### 引用作用域数组
394+
```c++
395+
int arr[5] = {1, 2, 3, 4, 5};
396+
// 引用作用于数组
397+
// 直接将数组名,替换为 &otherName, 但是因为[]的优先级更高,所以需要加上小括号
398+
int (&arr1)[5] = arr;
399+
400+
// 方法2:先给数组类型起一个别名,例如这里给int[5]的数组起一个为TYPE_ARR的别名
401+
typedef int TYPE_ARR[5];
402+
// TYPE_ARR newArr = {1, 2, 3, 4, 5};
403+
// 再给这个数组类型的别名来设置引用
404+
TYPE_ARR &myArr = arr;
405+
406+
for(int i = 0; i < 5; i++) {
407+
std::cout << arr1[i] << std::endl;
408+
}
409+
410+
for(int i = 0; i < 5; i++) {
411+
std::cout << myArr[i] << std::endl;
412+
}
413+
```
414+
393415
394416
##### 指针(pointer)
395417
指针是指向(point to)另外一种类型的复合类型。
@@ -593,22 +615,21 @@ const double *cptr = &pi; // 正确: cptr可以指向一个常量
593615
从标识符开始读,cptr是一个指针,它指向一个const double。
594616

595617

596-
###### 常量指针(const修饰指针)
618+
###### 指向常量的指针(const修饰指针)
597619

598620
```c++
599621
int a = 10;
600622
int b = 10;
601-
const int *p = &a; // 常量指针:指针的指向可以修改,但是指针指向的值不可以改
602-
*p = 20; // 错误,指针指向的值不可以改
603-
p = &b; // 正确,指针指向可以改
623+
// 常量指针:这里看指针的指向可以修改,但是指针指向的值不可以改
624+
// 这里p是一个什么类型的指针? p是一个const int类型,也就是说p是一个指向常量的指针,指向的是一个常量,常量是不能修改的。
625+
const int* p = &a;
626+
*p = 20; // 错误,指针指向的是一个常量值,值不可以改
627+
p = &b; // 正确,指针可以改
604628
```
605-
一个简单的记法就是:
606-
`const int *p`,那const就是修饰的 `*p`,也就是指针指向的值是不能修改的。
607-
608-
609-
###### 指针常量(const修饰常量)
629+
###### 指针常量
610630
```c++
611-
int * const p = &a; //指针的指向不可以改,但是指针指向的值可以改
631+
// p还是一个int *类型的指针,所有他指向的值是一个int类型的值,是可以修改的
632+
int * const p = &a; //指针的指向不可以改,但是指针指向指向的值可以改
612633
*p = 20; // 正确,指向的值可以改
613634
p = &b; // 错误,指针指向不可以改
614635
```

C++入门/2.类.md

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,53 @@ Stock garment("Furry", 50, 2.5); // 与上面等价
111111
112112
food.show();
113113
```
114+
### static修饰成员变量
115+
116+
- 静态数据成员不属于某个对象,在为对象分配空间中不包括静态成员所占空间。
117+
- 静态变量,是在编译阶段就分配空间,对象还没有创建时,就已经分配空间。
118+
- 静态成员变量必须在类中声明,在类外定义。
119+
120+
Data.h
121+
```c++
122+
class Data {
123+
private:
124+
int num;
125+
char c;
126+
public:
127+
static int a1;
128+
static int b;
129+
};
130+
```
131+
132+
Data.cpp
133+
```c++
134+
#include "Data.h"
135+
136+
int Data::a1 = 0;
137+
int Data::b = 0;
138+
```
139+
140+
main.cpp
141+
```c++
142+
using namespace std;
143+
int main() {
144+
cout << sizeof(Data) << endl;
145+
}
146+
```
147+
这里Data的大小是8,为什么是8呢?
148+
这是因为内存对齐。
149+
需要内存对齐的原因:
150+
1,32位系统cpu一次寻址4个字节,64位系统一次寻址8个字节
151+
152+
以64位系统为列:CPU一次寻址都是从地址为8的倍数的地址开始寻址,如果存储的数据都是内存对齐的,即每一个数据的首地址也都是存放在以8为倍数的地址中,那么CPU一次寻址就可以读取整个数据。
153+
154+
如果没有内存对齐,数据都是一个接着一个存储的。那么为了访问未对齐的数据的内存,CPU处理器一次读取的内存数据(8字节)可能包含两个数据的存储数据,而导致数据读取不完整,需要作两次内存访问;而对齐的内存访问仅需要一次访问。
155+
156+
2,为了可以在不同平台上兼容。
157+
158+
基本数据类型的内存对齐:
159+
计算机系统对基本类型数据在内存中放的位置做了限制,它们会要求这些数据的首地址是一个数(一般为4---32位系统或者8---64位系统)的整数倍,也就是说这些数据的首地址被放到4/8的整数倍的地址中。
160+
https://blog.csdn.net/weixin_48896613/article/details/127371045
114161

115162
### 默认构造函数
116163

@@ -279,11 +326,56 @@ int main(int argc, const char * argv[]) {
279326

280327

281328
含有纯虚函数的类就是Java中的接口。是不能实例化的。
282-
含有虚函数的类,析构函数也应该声明为虚函数。在delete父类指针的时候,会调用子类的析构函数,实现完整析构。
329+
330+
331+
>>> 含有虚函数的类,析构函数也应该声明为虚函数。
332+
333+
>>> 这样在delete父类指针的时候,才会调用子类的析构函数,实现完整析构。
283334
284335
实现多态性:
285336
在C++语言中实现多态性,需在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
286337

338+
在 C++ 中,虚函数的实现原理基于两个关键概念:虚函数表和虚函数指针。
339+
340+
虚函数表:每个包含虚函数的类都会生成一个虚函数表(Virtual Table),其中存储着该类中所有虚函数的地址。
341+
虚函数表是一个由指针构成的数组,每个指针指向一个虚函数的实现代码。
342+
虚函数指针:在对象的内存布局中,编译器会添加一个额外的指针,称为虚函数指针或虚表指针(Virtual Table Pointer,简称 VTable 指针)。
343+
这个指针指向该对象对应的虚函数表,从而让程序能够动态地调用正确的虚函数。
344+
当一个基类指针或引用调用虚函数时,编译器会使用虚表指针来查找该对象对应的虚函数表,并根据函数在虚函数表中的位置来调用正确的虚函数。
345+
346+
347+
### 虚析构
348+
349+
```c++
350+
Animal *base = new Cat();
351+
```
352+
如果使用默认构造函数的时候,执行完之后会发现,调用了父类的构造函数,然后接着调用了子类的构造函数,但是执行完成后只调用了父类的析构函数,并没有调用子类的析构函数。
353+
354+
这是因为base指向的类型是Animal,在没有设计虚析构的时候,只能调用父类的析构函数。
355+
356+
为了解决这个问题就要用虚析构。
357+
358+
虚析构的作用: 通过基类指针、引用释放子类的所有空间。
359+
虚析构: 在虚析构函数前加上virtual修饰。
360+
361+
###纯虚析构
362+
363+
364+
```c++
365+
class B {
366+
public:
367+
// virtual修饰,并加上0
368+
virtual ~B() = 0;
369+
};
370+
371+
// 纯虚析构必须实现析构函数的函数体
372+
B::~B() {
373+
374+
}
375+
```
376+
原因:通过基类指针释放了类对象时,会先调用子类析构,再调用父类析构(如果父类的析构不实现,那就无法实现调用)
377+
378+
287379
#### 模板
288380
289381
模板(可以理解为java的泛型)是实现代码重用机制的一种工具,它可以实现参数类型化,即把参数定义为类型,从而实现代码的可重用性。同时,模板能够减少源代码量并提高代码的机动性,却不会降低类型安全。

C++入门/3.运算符重载.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
3.运算符重载
2+
---
3+
4+
5+
=,[],()和->操作符只能通过成员函数进行重载。
6+
7+
<< 和 >> 只能通过全局函数配合友元函数进行重载。
8+
9+
不要重载&&和||操作符,因为无法实现短路规则
10+
11+
MyString.h
12+
```c++
13+
//
14+
// Created by xuchuanren on 2023/11/15.
15+
//
16+
17+
#ifndef CPPDEMO_MYSTRING_H
18+
#define CPPDEMO_MYSTRING_H
19+
20+
#include <iostream>
21+
22+
using namespace std;
23+
24+
class MyString {
25+
// 声明友元
26+
friend istream &operator>>(istream &in, MyString &ob);
27+
28+
friend ostream &operator<<(ostream &out, MyString &ob);
29+
30+
private:
31+
char *str;
32+
int size;
33+
34+
public:
35+
MyString();
36+
37+
MyString(const char *str);
38+
39+
MyString(const MyString &ob);
40+
41+
~MyString();
42+
43+
int getSize() const;
44+
45+
char &operator[](int pos);
46+
47+
MyString &operator=(const MyString &str);
48+
49+
MyString &operator=(const char *str);
50+
51+
MyString &operator+(const MyString &ob);
52+
};
53+
54+
55+
#endif //CPPDEMO_MYSTRING_H
56+
57+
```
58+
59+
MyString.cpp
60+
```c++
61+
//
62+
// Created by xuchuanren on 2023/11/15.
63+
//
64+
65+
#include "MyString.h"
66+
#include <iostream>
67+
68+
using namespace std;
69+
70+
MyString::MyString() {
71+
str = nullptr;
72+
size = 0;
73+
cout << "no paramter constructor" << endl;
74+
}
75+
76+
MyString::MyString(const char *str) {
77+
this->str = new char[strlen(str) + 1];
78+
strcpy(this->str, str);
79+
size = strlen(str);
80+
cout << "parameter constructor" << endl;
81+
}
82+
83+
MyString::MyString(const MyString &ob) {
84+
this->str = new char[strlen(ob.str) + 1];
85+
strcpy(str, ob.str);
86+
size = ob.size;
87+
cout << "copy constructor" << endl;
88+
}
89+
90+
int MyString::getSize() const {
91+
return size;
92+
}
93+
// 因为<<中要用到类外的ostream,所以要用全局函数来实现重载运算符
94+
// 但是在全局函数中又要用到MyString中的属性,所以要在头文件中声明为友元函数
95+
ostream &operator<<(ostream &out, MyString &ob) {
96+
out << ob.str << endl;
97+
return out;
98+
}
99+
100+
istream &operator>>(istream &in, MyString &ob) {
101+
if (ob.str != nullptr) {
102+
delete[] ob.str;
103+
ob.str = nullptr;
104+
}
105+
106+
char buf[1024] = "";
107+
in >> buf;
108+
ob.str = new char[strlen(buf) + 1];
109+
strcpy(ob.str, buf);
110+
ob.size = strlen(buf);
111+
return in;
112+
}
113+
114+
char &MyString::operator[](int index) {
115+
if (index >= 0 && index < size) {
116+
return str[index];
117+
} else {
118+
cout << "invalid index" << endl;
119+
}
120+
}
121+
// =号运算符的重载不会用到外部的类,用成员函数实现重载即可
122+
MyString &MyString::operator=(const MyString &ob) {
123+
if (str != nullptr) {
124+
delete[] str;
125+
str = nullptr;
126+
}
127+
str = new char[ob.size + 1];
128+
strcpy(str, ob.str);
129+
size = ob.size;
130+
return *this;
131+
}
132+
133+
MyString::~MyString() {
134+
if (str != nullptr) {
135+
delete[] str;
136+
str = nullptr;
137+
}
138+
cout << "deconstructor" << endl;
139+
}
140+
141+
MyString &MyString::operator=(const char *str) {
142+
if (this->str != nullptr) {
143+
delete[] this->str;
144+
this->str = nullptr;
145+
}
146+
this->str = new char[strlen(str) + 1];
147+
strcpy(this->str, str);
148+
size = strlen(str);
149+
return *this;
150+
}
151+
152+
MyString &MyString::operator+(const MyString &ob) {
153+
int newSize = this->size + ob.size;
154+
char *tempStr = new char[newSize + 1];
155+
memset(tempStr, 'c', newSize + 1);
156+
cout << "size : " << tempStr << endl;
157+
strcpy(tempStr, this->str);
158+
strcat(tempStr, ob.str);
159+
cout << "size : " << tempStr << endl;
160+
static MyString newString(tempStr);
161+
if (tempStr != nullptr) {
162+
delete[] tempStr;
163+
tempStr = nullptr;
164+
}
165+
return newString;
166+
}
167+
```

C++入门/4.动态内存.md

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ C++标准库提供了四种指针来管理底层指针的方式:
8484
- std::unique_ptr:独占式指针,同一个时间内只有一个指针能够指向该对象,当然,该对象的拥有权是可以移交出去的。
8585
- std::auto_ptr:C++98中提出的,目前已经完全被std::unique_ptr取代。
8686
- std::weak_ptr:它是一种弱引用,指向shared_ptr所管理的对象。弱引用可以理解成是监视shared_ptr(强引用)的生命周期用的,是一种对shared_ptr的扩充,不是一种独立的智能指针,不能用来操作所指向的资源,所以它看起来像是一个shared_ptr的助手。所以它的智能也就智能在能够监视到它所指向的对象是否存在了。
87+
weak_ptr不会产生强引用,因此可以很好的解决互相引用的问题.
88+
8789
作为智能指针,程序员不用担心内存的释放问题,即便忘记了delete,系统也能够帮助程序员delete,这是智能指针的本职工作。
8890

8991
```c++
@@ -154,9 +156,31 @@ double cube(double x); // cube函数的头
154156
由于malloc()和free()是库函数而不是运算符,它们不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc和free函数。
155157
因此,C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。
156158

157-
- malloc/free不能执行构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。而相比之下,使用new和delete实现初始化和释放内存则简单得多。
159+
- malloc返回一个void *指针,c++不允许将void *赋值给其他任何指针,必须强转。
160+
- malloc可能申请内存失败,所以必须判断返回值来确保内存分配成功。
161+
- 重要: malloc/free不会调用构造函数与析构函数,必须调用成员函数Initialize和Destroy来完成初始化与清除工作。
158162
- new/delete不是C++的库函数,而是运算符,而malloc/free才是C和C++的标准库函数。
159163

164+
165+
### 类型转换
166+
167+
```c++
168+
const Person *p1 = new Person();
169+
Person *p2 = const_cast<Person *>(p1);
170+
Person *p3 = (Person *)p1;
171+
```
172+
#### c风格类型转换
173+
- (type)expression
174+
- type(expression)
175+
#### C++风格类型转换
176+
- const_cast: 用于const类型的指针转换为非const类型
177+
- dynamic_cast:用于多态类型的转换,有运行时安全检测
178+
- static_cast:相对于dynamic_cast,缺乏运行时安全检测,用于基本数据类型的转换,把非const转成const。
179+
- reinterpret_cast:属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝。
180+
181+
182+
183+
160184
### STL
161185
STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室所开发出来的。现在虽说它主要出现在C++中,但在被引入C++之前,该技术就已经存在了很长一段时间。STL的目的是标准化组件,用户不用重新开发它们,而可以使用这些现成的组件。STL现在是C++的一部分,因此不用额外安装什么,其被内建在编译器之内。
162186

C++入门/7.C++提高编程.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2152,7 +2152,6 @@ int main() {
21522152
21532153
* `push_back(ele);` //尾部插入元素ele
21542154
* `pop_back();` //删除最后一个元素
2155-
* `insert(const_iterator pos, ele);` //迭代器指向位置pos插入元素ele
21562155
* `insert(const_iterator pos, int count,ele);`//迭代器指向位置pos插入count个元素ele
21572156
* `erase(const_iterator pos);` //删除迭代器指向的元素
21582157
* `erase(const_iterator start, const_iterator end);`//删除迭代器从start到end之间的元素

Qt/2.Qt常用组件.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ void setPixmap(const QPixmap &)
287287
首先定义QPixmap对象
288288
QPixmap pixmap;
289289
然后加载图片
290-
pixmap.load(":/Image/boat.jpg");
290+
pixmap.load(":/Image/boat.jpg"); // :表示资源文件
291291
最后将图片设置到QLabel中
292292
QLabel *label = new QLabel;
293293
label.setPixmap(pixmap);

linux/.3.进程间通信.md.swp

20 KB
Binary file not shown.
File renamed without changes.

0 commit comments

Comments
 (0)