c++笔记

C++结构体赋值

C++ 中,可以在结构体中对数据进行赋值,赋值方式和限制需要注意

直接在成员声明时初始化(C++11 及以后支持)

C++11 引入了非静态成员初始化器,允许在结构体定义时直接为成员指定默认值,语法类似变量初始化:

1
2
3
4
5
6
struct MyStruct {
int a = 10; // 基本类型直接赋值
double b = 3.14; // 浮点型默认值
std::string c = "hello"; // 类类型默认值
int arr[3] = {1, 2, 3}; // 数组初始化
};

创建结构体对象时,若未显式赋值,成员会使用这些默认值:

1
2
MyStruct s;
cout << s.a; // 输出 10

通过构造函数赋值(最常用方式)

C++ 结构体可以像类一样定义构造函数,在构造函数中对成员进行初始化或赋值。这是更灵活的方式,支持根据参数动态设置值:结构体(struct)不仅可以包含数据成员,还可以定义各种函数,包括成员函数、构造函数、析构函数、静态函数等,这一点与类(class)几乎完全一致。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct Person {
std::string name;
int age;

// 构造函数:初始化成员
Person(std::string n, int a) {
name = n; // 赋值
age = a;
}

// 无参构造函数(若定义了带参构造,需显式定义无参构造才可用)
Person() {
name = "unknown";
age = 0;
}
};

// 使用
Person p1("Alice", 20); // name="Alice", age=20
Person p2; // name="unknown", age=0

使用初始化列表(更高效的初始化方式)

构造函数中可以通过初始化列表直接初始化成员(而非赋值),性能更优(尤其对于类类型成员)

1
2
3
4
5
6
7
struct Point {
int x;
int y;

// 初始化列表:直接初始化成员
Point(int a, int b) : x(a), y(b) {}
};

静态成员的初始化(需在结构体外部定义)

若结构体包含静态成员(属于整个结构体,而非某个对象),其初始化必须在结构体外部进行(类内只能声明):

1
2
3
4
5
6
struct Test {
static int count; // 声明静态成员
};

// 外部初始化(全局作用域)
int Test::count = 0;
  • 结构体与类的核心区别仅在于默认访问权限struct 默认为 publicclass 默认为 private),其他功能完全一致。

引用拷贝

引用拷贝是传递数据的两种核心方式,它们的选择取决于场景需求;而函数重载可以根据参数是引用还是拷贝,实现不同逻辑。

  • 引用(&:变量的 “别名”,指向原始数据的内存地址,操作引用等同于操作原始数据(无内存拷贝)。
  • 例:int a = 10; int& b = a; 中,ba 的引用,修改 b 会同时改变 a
  • 拷贝:创建原始数据的副本,新变量与原始数据占用独立内存,修改拷贝不影响原始数据(有内存开销)。
  • 例:int a = 10; int b = a; 中,ba 的拷贝,修改 b 不影响 a

类成员函数指针

类成员函数指针 ≠ 普通函数指针

声明格式

1
返回值类型 (类名::*指针名)(参数列表);

实例

1
2
3
4
5
6
7
8
9
class MyClass
{
public:
void func(int a) { }
void funcb(){ this->*pFunc(10)}
};

// 声明成员函数指针
void (MyClass::*pFunc)(int) = &MyClass::func;

调用格式(必须用对象 / 指针 + .* / ->*

1
2
3
4
5
MyClass obj;
(obj.*pFunc)(10); // 对象用 .*

MyClass* p = &obj;
(p->*pFunc)(10); // 指针用 ->*

普通函数指针 的区别(超级重要)

项目 普通函数指针 类成员函数指针
写法 void(*p)() void(MyClass::*p)()
存储 仅存地址 地址 + 偏移 / 信息(处理多继承)
大小 4/8 字节 可能 8/12/16 字节
调用 p() (obj.*p)()
隐含 this 有 this
能否直接当回调 不能直接用

特点

成员函数指针自带 this 信息

它知道自己属于哪个类,调用时必须绑定一个对象才能执行。

不能单独调用

1
pFunc(10); // ❌ 编译失败

修改成:

1
(obj.*pFunc)(10); // ✅

多继承 / 虚继承下,成员指针更复杂

因为对象布局变了,指针需要存储偏移信息,所以体积更大。

类型非常严格

A::funcB::func 不能互相赋值,即使签名一样。

完整可运行示例

示例一:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
using namespace std;

class MyClass
{
public:
void show(int a) {
cout << "a = " << a << endl;
}
};

int main()
{
// 1. 定义成员函数指针
void (MyClass::*pFunc)(int) = &MyClass::show;

// 2. 创建对象
MyClass obj;

// 3. 调用
(obj.*pFunc)(100);

return 0;
}

示例二:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class MyClass
{
public:
void func(int a) { }

// 1. 声明成员函数指针
void (MyClass::*pFunc)(int);

void funcb()
{
// 2. 赋值(指向自己的成员函数)
pFunc = &MyClass::func;

// 3. 正确调用语法
(this->*pFunc)(10); // ✅ 正确
}
};