<> 与 “”引用的区别

“”

image-20241024164406720

<>

image-20241024164804178

image-20241024164916065

单例类

c++
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
class Singleton
{
private:
static Singleton* s_Instance;
public:
static Singleton& Get(){ return *s_Instance;}
void hello(){};
};
Singleton* Singleton::s_Instance = nullptr;
int main(){
//调用方法
Singleton::Get().hello();
};


/*****************************/
//另一种写法
/* class Singleton
{
public:
static Singleton& Get(){
static Singleton instance;
return instance;
}
void hello(){};
};
*/
int main(){
//调用方法
Singleton::Get().hello();
}

构造函数

比如我们有一个类——Entity,如果不手动定义一个构造函数,那么编译器会默认为我们构造一个空的构造函数

例如:

c++
1
2
3
//每创建一个实例就会调用这个构造函数
Entity(){
}
c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Entity
{
public:
float x, y;
Entity(float x, float y){
X = x;
Y = y;
}
void print(){
std::cout << X << "," << Y << std::endl;
}
};
//为了实现print其实也可以直接把print放在构造函数里
//缺点:每创建一次实例就会调用一次print
int main(){
Entity e(10.0f, 5.0f);
e.Print();
std::cin.get();
}
c++
1
2
3
4
5
6
7
8
9
10
11
12
class Log
{
private:
Log(){
}
//Log() = delete; 这句代码可以去掉这个类的构造函数
//删去构造函数之后使用 类似的Log l创造实例会报错
public:
static void Write(){

}
};

析构函数

c++
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
class Entity
{
public:
float x, y;
Entity(){
X = 0.0f;
Y = 0.0f;
std::cout << "Created Entity !" << std::endl;
}
void print(){
std::cout << X << "," << Y << std::endl;
}
~Entity(){
std::cout << "Destroyed Entity !" << std::endl;
}
};

void Function(){
Entity e;
e.Print();
}

int main(){
Function();
std::cin.get();
}

手动调用析构函数

c++
1
e.~Entity();

继承

c++
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
class Entity
{
public:
float X, Y;

void Move(float xa, float ya){
X += xa;
Y += ya;
}
};

class Player : public Entity
{
public:
const char* Name;

void PrintName()
{
std::cout << Name << std::endl;
}
}

int main(){
std::cin.get();
}

虚函数

用于实现继承关系中子类(派生类)对父类(基类)方法的重写

c++
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
class Entity
{
public:
std::string GetName(){ return "Entity"; }
};

class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}

std::string GetName() {return m_Name; }
};

int main(){
Entity* e = new Entity();
std::cout << e->GetName() << std::endl;

Player* p = new Player("Cherno");
std::cout << p->GetName() << std::endl;
/*
*Entity* entity = p;
*std::cout << entity->GetName() << std::endl;//输出为Entity
*/
std::cin.get();

}

上述代码还可以写成

c++
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
class Entity
{
public:
std::string GetName(){ return "Entity"; }
};

class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}

std::string GetName() {return m_Name; }
};

void PrintName(Entity* entity)
{
std::cout << entity->GetName() << std::endl;
}

int main(){
Entity* e = new Entity();
PrintName(e);

Player* p = new Player("Cherno");
PrintName(p); //这个地方p既是Player类型也是Entity类型
std::cin.get();

}

当你运行上述两段代码你会发现,对于Entity均输出了两次,因为总是优先去该类(Entity类里找GetName函数),所以为了让Player和Entity中的GetName各司其职,我们可以引入虚函数,实现覆写(override)需要将基类中的基函数标记为虚函数

于是修改代码

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Entity
{
public:
virtual std::string GetName(){ return "Entity"; }
};

class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}

std::string GetName() override {return m_Name; }
};

事实上我们没写override前,依然可以输出我们想要的结果,但是加上override可以提高代码可读性并且方便进行debug,比如函数名拼写错误,会报error(因为基函数里根本没有这个函数)

此处有一种C++语法——初始化列表

初始化列表是 C++ 中的一种语法,用来在构造函数中直接初始化类的成员变量。它的语法是在构造函数的参数列表和函数体之间使用冒号 :,后面跟随成员变量的初始化方式。

  • 可以提高性能,可以先对类成员变量进行赋值,再用默认构造函数创建一个空字符串。

  • 强制初始化:有些类的成员变量必须通过初始化列表进行初始化。例如:

    • const成员变量(不能在构造函数体中赋值,只能在初始化列表中初始化)
    • 引用类型成员变量(必须在创建时就被初始化,无法通过赋值修改)
  • 初始化的顺序只与在类中的声明顺序有关,与初始化列表中的顺序无关

ClassName(参数列表) : 类成员1(参数), 类成员2(参数), ... { // 构造函数体 }

关于new

常见用法

c++
1
2
3
4
5
classname* example = new classname(); //delete example 

int* p = new int(5);//delete p

int* arr = new int[10]//分配大小为10的整型数组 delete[] arr

new与malloc的对比

  1. 构造函数和析构函数的调用

    • new 会调用类对象的构造函数,而 malloc 只分配内存,不会调用构造函数。
    • 释放时,delete 会调用析构函数,而 free 不会调用析构函数。
    c++
    1
    2
    3
    4
    5
    Entity* e1 = new Entity();  // 调用构造函数
    delete e1; // 调用析构函数

    Entity* e2 = (Entity*)malloc(sizeof(Entity)); // 仅分配内存,不调用构造函数
    free(e2); // 仅释放内存,不调用析构函数
  2. 类型安全

    • new 会返回具体类型的指针,不需要进行显式类型转换。
    • malloc 返回 void*,需要进行强制类型转换。
    c++
    1
    2
    int* p1 = new int(5);  // 不需要强制转换
    int* p2 = (int*)malloc(sizeof(int)); // 需要强制转换
  3. 内存分配失败处理

    • 如果 new 分配内存失败,会抛出 std::bad_alloc 异常。
    • malloc 返回 NULL,需要检查返回值是否为 NULL

注:**nothrow 形式**:如果不希望 new 抛出异常,可以使用 nothrow 形式:

c++
1
2
3
4
5
int* p = new(std::nothrow) int;
if (p == nullptr)
{
std::cout << "Memory allocation failed" << std::endl;
}`

当内存分配失败时,new会返回nullptr而不是抛出异常

纯虚函数(接口)

允许我们在基类中定义一个没有实现的函数,然后强制子类去实现该函数

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Entity
{
public:
virtual std::string GetName() = 0;//意味着这个函数成为了纯虚函数,并且必须在一个子类中实现,如果想要实例化一个子类,则这个子类需要实现这个函数
};

class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}

std::string GetName() override {return m_Name; }
};

c++
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
class Printable
{
public:
virtual std::string GetClassName() = 0;
};

class Entity : public Printable
{
public:
virtual std::string GetName(){ return "Entity"; }
std::string GetClassName() override {return "Entity";}
};
//class Player : public Entity, Printable实现一个接口,如果Player不是继承于Entity的话,必须实现这个接口
class Player : public Entity
{
private:
std::string m_Name;
public:
Player(const std::string& name)
: m_Name(name) {}

std::string GetName() override {return m_Name; }
std::string GetClassName() override {return "Player";}
};

void Print(Printable* obj)
{
std::cout << obj->GetClassName() << std::endl;
}

int main(){
Entity* e = new Entity();

Player* p = new Player("Cherno");


std::cin.get();

}

字符串字面量

字符串字面量是存储在内存中的只读部分的

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main()
{
//初始化字符串
std::string name = "cherno";
name += "hello";//等同于 std::string name = std::string("cherno") + "hello";
const char* name1 ="cherno";
char name3[] = "cherno";
//此处字符串还是存在内存的只读部分的
//修改时创造了一个新的变量即(name3)进行copy再修改而不是直接对常量字符串进行修改
name3[2] = 'a'
using namespace std::string_literals;
std::string name0 = U"cherno"s + U"hello";//相当于std::u32string name0

const char* example = R"(Line1
Line2
Line3
Line4)";

//上述在双引号前加R等价于下面的代码
const char* ex = "Line1\n"
"Line2\n"
"Line3\n";

}

C++中的const

c++
1
2
3
const int* a //不能修改该指针指向的内容 和int const* a同义
int* const a //可以修改指针指向的内存中的数据,但不能修改指针的值
const int* const a;//指针的内容和指针指向的内存中的数据都不能修改

类中的const(下列中的用法只能在类中)

c++
1
2
3
4
5
6
7
8
9
10
class Entity
{
private:
int m_X, m_Y;
public:
int GetX() const//承诺不会修改类成员变量,只读
{ //m_X = 2; 类似的句子会报错
return m_X;
}
};
c++
1
2
3
4
5
6
7
8
9
10
11
12
class Entity
{
private:
int* m_X, m_Y;
public:
//指针的内容和指针指向的内存中的数据都不能修改
//并且函数也不能修改类中的内容,只能读取
const int* const GetX() const
{
return m_X;
}
};
c++
1
2
int* x, y; //x为int*类型,y为int类型
int*x, *y; //x,y均为int* 类型

const的高级用法

c++
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
class Entity
{
private:
int m_X, m_Y;
mutable int var;
public:
int GetX() const//常量方法
{
var = 2;//设置为mutable就可以修改,即使在常量方法中
return m_X;
}
int GetX()
{
return m_X;
}
};

void PrintEntity(const Entity& e)
{
//默认调用int GetX() const
//调用int GetX()会报错,因为不能确保这个函数不修改变量
std::cout << e.GetX() << std::endl;
}

int main()
{
Entity e;
}

mutable

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//类中的mutable
class Entity
{
private:
std::string m_Name;
mutable int m_DebugCount = 0;
public:
const std::string& GetName() const
{
m_DebugCount++;
return m_Name;
}
};

int main()
{
const Entity e;
e.GetName();
}

成员初始化列表

c++
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
class Entity
{
private:
std::string m_Name;
public:
Entity()
: m_Name("Unknown")
{
}

Entity(const std::string& name)
: m_Name(name)
{
}
const std::string& GetName() const {return m_Name; }
}

int main()
{
Entity e0;
std::cout << e0.GetName() << std::endl;

Entity e1;
std::cout << e1.GetName() << std::endl;

std::cin.get();
}

通过以下代码了解为什么要使用 成员初始化列表

c++
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
#include <iostream>
#include <string>

class Example
{
public:
Example()
{
std::cout << "Created Entity!" << std::endl;
}
Entity(int x)
{
std::cout << "Created Entity with" << x << "!" << std::endl;
}
};

class Entity
{
private:
std::string m_Name;
Example m_Example;
public:
Entity()
{
m_Name = std::string("Unknown");
m_Example = Example(8);
}
/* Entity()
* : m_Example(Example(8))
* {
* m_Name = std::string("Unknown");
* }
* 将上述构造函数换成注释函数,输出结果为 Created Entity with 8!
*/
Entity(const std::string& name)
: m_Name(name)
{
}

const std::string& GetName() const { return m_Name; }
}

int main()
{
Entity e0;
std::cin.get();
}

上述代码输出结果为

plaintext
1
2
Created Entity!
Created Entity with 8!

隐式转换implicit与explicit关键字

c++
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
class Entity
{
private:
std::string m_Name;
int m_Age;
public:
Entity(const std::string& name)
: m_Name(name) {}
Entity(int age)
: m_Name("Unknown"), m_Age(age)
};

void PrintEntity(const Entity& entity)
{
//Printing
}

int main()
{
PrintEntity(22);
PrintEntity(Entity("Cherno"))

Entity a = "Cherno";
Entity b = 22;
//常用写法
//Entity a("Cherno");
//Entity b(22);
std::cin.get();
}

explicit可以禁用上述的隐式构造,用法:放在构造函数之前

所以上述代码可以变为

c++
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
class Entity
{
private:
std::string m_Name;
int m_Age;
public:
explicit Entity(const std::string& name)
: m_Name(name) {}
explicit Entity(int age)
: m_Name("Unknown"), m_Age(age)
};

void PrintEntity(const Entity& entity)
{
//Printing
}

int main()
{
PrintEntity(22);//会报错
PrintEntity(Entity("Cherno"))

Entity a = "Cherno";//会报错
Entity b = 22;//会报错必须修改为显示调用构造函数,例如下面注释掉的代码
//Entity a("Cherno");
//Entity b(22);
std::cin.get();
}

运算符及其重载

没有使用运算符重载前

c++
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
#include <iostream>
#include <string>

struct Vector2
{
float x, y;

Vector2(float x, float y)
: x(x), y(y) {}
Vector2 Add(const Vector2& other) const
{
return Vector2(x + other.x, y+ other.y);
}
Vector2 Multiply(const Vector2& other) const
{
return Vector2(x * other.x, y * other.y);
}
};

int main()
{
Vector2 position(4.0f, 4.0f);
Vector2 speed(0.5f, 1.5f);
Vector2 powerup(1.1f, 1.1f);

Vector2 result = position.Add(speed.Multiply(powerup));
std::cin.get();
}

进行运算符重载

c++
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
#include <iostream>
#include <string>

struct Vector2
{
float x, y;

Vector2(float x, float y)
: x(x), y(y) {}
Vector2 Add(const Vector2& other) const
{
return Vector2(x + other.x, y+ other.y);
}

Vector2 operator+(const Vector2& other) const
{
return Add(other);
}

Vector2 Multiply(const Vector2& other) const
{
return Vector2(x * other.x, y * other.y);
}

Vector2 operator*(const Vector2& other) const
{
return Multiply(other);
}

bool operator==(const Vector2& other) cosnt
{
return x == other.x && y == other.y;
}

bool operator!=(const Vector2& other) cosnt
{
//return operator==(other);
return !(*this == other);
}

bool operator==(const Vector2& other) const
{
return x== other.x && y == other.y;
}

bool operator!=(const Vector2& other) const
{
//return operator==(other)
return !(*this == other);
}
};

std::ostream& operator<<(std::ostream& stream, const Vector2& other)
{
stream << other.x << ", " << other.y;
return stream;
}

int main()
{
Vector2 position(4.0f, 4.0f);
Vector2 speed(0.5f, 1.5f);
Vector2 powerup(1.1f, 1.1f);

Vector2 result1 = position.Add(speed.Multiply(powerup));
Vector2 result2 = position + speed * powerup;

if(result1 == result2)

std::cout << result2 << std::endl;

std::cin.get();
}

函数调用也可以进行重载,因为调用方式非常类似于函数调用,所以又称仿函数

this关键字

c++
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
#include <iostream>
#include <string>

void PrintEntity(const Entity& e);

class Entity
{
public:
int x, y;

// Entity(int x, int y)
// : x(x), y(y)
// {
// }
Entity(int x, int y)
: x(x), y(y)
{
this->x = x;
this->y = y;

Entity& e = *this;

PrintEntity(*this);
}

int GetX() cosnt
{
const Entity& e = *this;
}
};

void PrintEntity(const Entity& e)
{
//Print
}

对象的生存期(栈作用域生存期)

c++
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
//作用域指针
#include <iostream>

class Entity
{
public:
Entity()
{
std::cout << "Entity created." << std::endl;
}
~Entity()
{
std::cout << "Entity destroyed." << std::endl;
}
};

class ScopedPtr
{
private:
Entity* m_Ptr;
public:
ScopedPtr(Entity* ptr)
: m_Ptr(ptr)
{
}

~ScopedPtr()
{
delete m_Ptr;
}
};

int main()
{
{
//相同的写法
//ScopedPtr e(new Entity());
ScopedPtr e = new Entity(); // 修正构造函数的调用
} // 在这里作用域结束,ScopedPtr 会自动释放 Entity 的内存

std::cin.get();
}

智能指针(smart_ptr)

实现自动化new & delete堆上内存

最简单的智能指针 unique_ptr, unique_ptr不能被复制,因为多个unique_ptr会导致内存被释放后,其他unique_ptr处于没有引用的悬空

c++
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
#include <iostream>
#include <memory>

class Entity
{
public:
Entity()
{
std::cout << "Entity created." << std::endl;
}
~Entity()
{
std::cout << "Entity destroyed." << std::endl;
}

};

int main()
{
{
//std::unique_ptr<Entity> entity(new Entity());
//相较于上述代码,这个代码可以防止构造函数异常导致的没有引用的悬空指针
std::unique_ptr<Entity> entity = std::make_unique<Entity>();
}
std::cin.get();
}

shared_ptr 可以实现引用计数,只有当引用次数为0之后,才会释放堆上new的内存

c++
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
#include <iostream>
#include <memory>

class Entity
{
public:
Entity()
{
std::cout << "Entity created." << std::endl;
}
~Entity()
{
std::cout << "Entity destroyed." << std::endl;
}

};

int main()
{
{
std::shared_ptr<Entity> e0;
{
std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
e0 = sharedEntity;
}
}//程序执行到此处才释放entity,打印台输出Entity destroyed.
std::cin.get();
}

weak_ptr 类似于shared_ptr ,但weak_ptr不会增加引用次数

c++
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
#include <iostream>
#include <memory>

class Entity
{
public:
Entity()
{
std::cout << "Entity created." << std::endl;
}
~Entity()
{
std::cout << "Entity destroyed." << std::endl;
}

};

int main()
{
{
std::weak_ptr<Entity> e0;
{
std::shared_ptr<Entity> sharedEntity = std::make_shared<Entity>();
e0 = sharedEntity;
}//程序执行到此处就释放entity,打印台输出Entity destroyed.
}
std::cin.get();
}

C++拷贝构造函数

浅拷贝

c++
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
#include <iostream>
#include <string>

struct String
{
private:
char* m_Buffer;
unsigned int m_Size;
public:
String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, string, m_Size);
m_Buffer[m_Size] = 0;//如果不能保证原字符串最后有0,就手动添加,而不是复制原字符串末尾的
}

~String()
{
delete[] m_Buffer;
}

char& operator[](unsigned int index)
{
return m_Buffer[index];
}

friend std::ostream& operator<<(std::ostream& stream, const String& string);
};

std::ostream& operator<<(std::ostream& stream, const String& string)
{
stream << string.m_Buffer;
return stream;
}

int main()
{
String string = "Cherno";
//添加了这个代码后,程序运行结束时会报错
//原因是second类的 char* m_Buffer和string指向了同一块区域,所以两个类的析构函数共delete同一个区域两次了
//浅拷贝,只复制了值,没有保证都是不同的内存
String second = string;

second[2] = 'a';

std::cout << string << std::endl;
std::cout << second << std::endl;
std::cin.get();
}

深拷贝–拷贝构造函数,c++默认提供的拷贝构造函数为浅拷贝

c++
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
#include <iostream>
#include <string>

struct String
{
private:
char* m_Buffer;
unsigned int m_Size;
public:
String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, string, m_Size);
m_Buffer[m_Size] = 0;//如果不能保证原字符串最后有0,就手动添加,而不是复制原字符串末尾的
}

//C++ 提供的浅拷贝类似于下方的代码
// String(const String& other)
// : m_Buffer(other.m_Buffer), m_Size(other.m_Size)
// {
// }

//浅拷贝还可以写成
// String(const String& other)
// {
// memcpy(this, &other, sizeof(String));
// }

String(const String& other)
: m_Size(other.m_Size)
{
std::cout << "Copied String!";
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
}

~String()
{
delete[] m_Buffer;
}

char& operator[](unsigned int index)
{
return m_Buffer[index];
}

friend std::ostream& operator<<(std::ostream& stream, const String& string);
};

std::ostream& operator<<(std::ostream& stream, const String& string)
{
stream << string.m_Buffer;
return stream;
}

void PrintString(String string)
{
std::cout << string << std::endl;
}

int main()
{
String string = "Cherno";
//添加了这个代码后,程序运行结束时会报错
//原因是second类的 char* m_Buffer和string指向了同一块区域,所以两个类的析构函数共delete同一个区域两次了
//浅拷贝,只复制了值,没有保证都是不同的内存
String second = string;

second[2] = 'a';

PrintString(string);
PrintString(second);
std::cin.get();
}

结果输出——事实上PrintString函数在使用时进行了两次拷贝,可以通过引用来避免

image-20241030184729178

C++箭头操作符

c++
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
#include <iostream>
#include <string>

class Entity
{
public:
int x;
public:
void Print() const { std::cout << "Hello!" << std::endl; }
};

class ScopedPtr
{
private:
Entity* m_Obj;
public:
ScopedPtr(Entity* entity)
: m_Obj(entity)
{
}

~ScopedPtr()
{
delete m_Obj;
}

Entity* operator->()
{
return m_Obj;
}

const Entity* operator->() const
{
return m_Obj;
}
};

int main()
{
const ScopedPtr entity = new Entity();
entity->Print();

std::cin.get();
}

通过箭头操作符来获得内存中某个值的偏移量

c++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <string>

struct Vector3
{
float x, y, z;
};

int main()
{
int offset = (int)&((Vector3*)nullptr)->z;//输出为8
std::cout << offset << std::endl;

std::cin.get();
}

C++动态数组

c++
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
#include <iostream>
#include <string>

struct Vertex
{
float x, y ,z;
};

std::ostream& operator<<(std::ostream& stream, const Vertex& vertex)
{
stream << vertex.x << "," << vertex.y << "," << vertex.z;
return stream;
}
//确保通过引用传递参数,这样不会在其他函数调用该数组进行复制,减少开销
void Function(const std::vector<Vertex>& vertices)
{

}

int main()
{
std::vector<Vertex> vertices;
vertices.push_back({ 1, 2, 3 });
vertices.push_back({ 4, 5, 6 });
Function(vertices);

for (int i = 0; i < vertices.size(); i++)
std::cout << vertices[i] << std::endl;

vertices.erase(vertices.begin() + 1);

for(Vertex v : vertices)
std::cout << v << std::endl;

std::cin.get();
}