C++开发
迭代器
在vector容器里面,迭代器是一个指针类型,相当于int *之类的
begin,end返回的是迭代器类型
template<class T>
class MyVector {
T* start;
T* finish;
T* end_of_storage;
public:
using iterator = T*;
iterator begin() { return start; }
iterator end() { return finish; }
void push_back(const T& v) {
if (finish == end_of_storage) {
// 重新分配、更大容量,并搬移元素
}
new (finish) T(v);
++finish;
}
};在list里面,它是一个成员类
#include <iostream>
template <typename T>
class List {
private:
struct Node {
T data;
Node* next;
Node(const T& val) : data(val), next(nullptr) {}
};
Node* head;
Node* tail;
public:
List() : head(nullptr), tail(nullptr) {}
~List() {
Node* current = head;
while (current) {
Node* tmp = current;
current = current->next;
delete tmp;
}
}
void push_back(const T& value) {
Node* newNode = new Node(value);
if (!head)
head = tail = newNode;
else {
tail->next = newNode;
tail = newNode;
}
}
// ✅ 嵌套的迭代器类
class iterator {
Node* current;
public:
iterator(Node* ptr = nullptr) : current(ptr) {}
T& operator*() const { return current->data; }
iterator& operator++() {
if (current) current = current->next;
return *this;
}
bool operator!=(const iterator& other) const {
return current != other.current;
}
};
iterator begin() { return iterator(head); }
iterator end() { return iterator(nullptr); }
};总结:迭代器就是容器里面单位元素的指针类型,换句话,它是一个指向单位元素的指针类型
它只是一个类型,相当于int*
为什么有些函数可以不创建对象或者指针 直接调用?->static
普通函数
class A {
public:
void say() {
std::cout << "I am A" << std::endl;
}
};
int main() {
A a;
a.say(); // 表面上是这样
}
//实际
void A__say(A* this) {
std::cout << "I am A" << std::endl;
}
int main() {
A a;
A__say(&a); // 隐式 this 指针传入
}a.say() 本质是 say(&a),也就是把 this = &a
static声明的函数没有this指针,不需要创建对象|指针,像全局函数一样调用
堆和栈
| 特性 | 栈(Stack) | 堆(Heap) |
|---|---|---|
| 分配方式 | 自动(编译器完成) | 手动(程序员用 new) |
| 生命周期 | 函数结束自动销毁 | 程序员控制(或智能指针) |
| 分配速度 | 非常快(指针加减) | 相对较慢(系统分配器) |
| 内存大小 | 小(几 MB) | 大(可达 GB) |
| 易错风险 | 小 | 易内存泄漏、悬空指针 |
| 是否可返回值 | ❌ 不可返回引用 | ✅ 可返回指针或引用 |
| 创建对象方式 | T obj; | T* obj = new T; |
#include <iostream>
using namespace std;
void showStackAndHeap() {
int stackVar = 10;
int* heapVar = new int(20);
cout << "Stack variable address: " << &stackVar << endl;
cout << "Heap variable address: " << heapVar << endl;
delete heapVar; // 别忘了释放内存
}
int main() {
while(1){
showStackAndHeap();
}
return 0;
}每次调用都会导致重新申请堆空间,不释放内存,导致前面申请的没有释放,会导致运行占用增大,直到程序关闭,回收全部资源
在Qt里面
只要你用的是 QObject 派生类,并在 new 时传入了 parent,就不用手动释放内存,Qt 会帮你自动回收
你用的是非 QObject 的普通类(比如 STL 容器、QString、QDateTime 等):
- 这些类是值类型,不属于 Qt 的对象树;
- 但一般用栈对象(直接创建对象)就行,不用管释放(栈自动销毁);
为什么说C++是活的 动态绑定
结论:在编译时,动态的行为编译器无法预判感知(new对象:要在堆上,只有运行时才有堆,所以不行)
因为多态的特性,有些操作并不知道自己要调用哪些函数,比如
class A {
public:
int s;
virtual void test() {
cout << "A::test() 执行" << endl;
}
};
class B : public A {
public:
int data;
void test() {
cout << "B::test() 执行" << endl;
}
};
A* p = new B();
p->test();在编译时不能感知到new()的操作,对象都没有建立,只知道p指向了一个地方。
编译器只会执行一个模板操作,取p指向地方的前8字节得到虚表指针,call虚指针指向的函数,这个函数是谁就不知道了。只有运行起来了,new在堆上申请了内存,才能调用构造函数初始化对象,给虚表指针赋值,才知道call的是谁。
#include <iostream>
using namespace std;
class A {
public:
int s;
virtual void test() {
cout << "A::test() 执行" << endl;
}
};
class B : public A {
public:
int data;
void test() {
cout << "B::test() 执行" << endl;
}
};
int main() {
// A* a=new A();
// B* b = new B();
A* p = new B();
// p = new B();
// 打印对象内存地址
cout << "对象B的内存地址: " << p << endl;
// 打印两个成员函数的地址
cout << "A::test 函数地址: " << &A::test << endl;
cout << "B::test 函数地址: " << &B::test << endl;
// 动态绑定
cout << "\np->test() 输出: ";
p->test();
delete p;
return 0;
}在反汇编窗口,可以看见编译后,并不知道call的谁,只是套了个模板

如果把virtual去掉,那就没有多态,虚表,虚表指针了。这里编译后明确就知道被绑定死了


B的结构
左边的是偏移量,不是大小 +—base class A代表那是A的地盘
虚表指针,一个继承链只有一个,指向某个类的虚表 8字节;虚表,每个继承了虚函数的类都有
在派生类的构造函数后,会自动改变该继承链里虚表指针指向的虚表。比如最开始指向的是基类的虚表,后面就是派生类了。
所以这里虚表指针指向的是B

A* p = new B()
这里p指向这个B的空间,但是因为是A*类型的,只能指向派生类中A的部分。
但是B里面,A的虚表指针已经不是最开始的了,在B的构造函数执行时已经被改变
所以执行p->test()是B的test

