C++学习笔记——创建与使用库、处理多个返回值、模板

张开发
2026/6/8 7:47:59 15 分钟阅读
C++学习笔记——创建与使用库、处理多个返回值、模板
目录1. 创建与使用库2. 处理多个返回值2.1 输出参数2.2 std::pair / std::tuple2.3 返回Array/Vector— 仅适用于同类型2.4 返回结构体3. 模板1. 创建与使用库步骤一在同一个“解决方案”下创建一个新项目例如一个“Engine”项目并将其“配置类型”设置为静态库(.lib)。步骤二在这个新项目中编写好代码并编译就会生成一个.lib文件。步骤三在主项目例如一个“Game”项目中可以通过“添加引用”的方式直接引用之前生成的静态库项目。这比手动配置路径更方便。2. 处理多个返回值2.1 输出参数函数不直接返回值而是通过引用或指针参数将结果“写入”到外部预先准备好的变量中。工作原理将函数声明为void并把想要“返回”的变量作为引用参数传入在函数内部修改它们。示例代码// 通过引用参数返回结果 void ParseShader(const std::string filepath, std::string vertexSrc, std::string fragmentSrc) { // ... 处理逻辑 vertexSrc ...; fragmentSrc ...; } int main() { std::string vertex, fragment; // 调用前需要预先创建变量 ParseShader(shader.glsl, vertex, fragment); return 0; }优点性能最优函数内部直接修改外部内存没有额外的拷贝。表达意图通过给参数命名如outResult可以明确哪些是输入、哪些是输出。缺点必须在函数调用前就创建好所有变量调用时参数列表变得冗长同时修改函数外部状态代码清晰度不高可读性较差。2.2 std::pair / std::tupleC11 引入了std::pair处理两个值和std::tuple处理任意多个值。工作原理函数直接返回一个包含所有结果的std::pair或std::tuple对象。示例代码#include tuple #include string // 返回一个 tuple std::tuplestd::string, std::string ParseShader(const std::string filepath) { return { ..., ... }; } int main() { auto result ParseShader(shader.glsl); // 通过 std::get索引 访问索引的含义不明确 std::string vertex std::get0(result); std::string fragment std::get1(result); return 0; }优点编写快速不需要提前定义数据结构。缺点访问成员时必须使用.first、.secondstd::pair或std::get索引std::tuple可读性极差无法直接看出每个字段代表什么。2.3 返回Array/Vector— 仅适用于同类型如果返回的多个值类型相同可以使用std::array或std::vector。工作原理函数将所有结果放入一个容器中返回。示例代码#include vector // 返回多个 int std::vectorint GetNumbers() { return {1, 2, 3}; }优点适合返回数量不定的同类型数据集合。缺点无法处理不同类型的数据。对于少量、固定数量的返回值使用容器会带来不必要的开销和复杂性。2.4 返回结构体工作原理为返回值专门定义一个结构体结构体的成员变量就是每个返回值。然后函数返回这个结构体类型的实例。示例代码// 定义一个清晰的结构体来包装返回值structShaderSources{ std::string VertexSource; std::string FragmentSource; };ShaderSourcesParseShader(conststd::string filepath){// ... 处理逻辑return{...,...}; }intmain(){ ShaderSources sources ParseShader(shader.glsl);// 通过有意义的成员名访问代码清晰明了std::cout sources.VertexSource std::endl;return0; }优点语义清晰、可读性极佳通过成员名可以清楚知道每个数据的含义。性能无损现代 C 编译器有返回值优化Return Value Optimization, RVO可以避免额外的拷贝开销。缺点需要编写额外的结构体代码。但对于提升代码质量来说这点开销是值得的。3. 模板模板是 C 实现泛型编程的核心工具它允许编写与类型无关的代码并由编译器在编译时根据具体类型生成对应的函数或类。整个过程发生在编译期没有任何运行时开销。使用templatetypename T进行声明然后用T代替具体的类型。#include iostream #include string // 声明一个函数模板 templatetypename T void Print(T value) { std::cout value std::endl; } int main() { // 使用方式1: 隐式实例化编译器根据参数 5 推断出 T int Print(5); // 使用方式2: 显式实例化直接指定 T std::string Printstd::string(Hello); // 隐式实例化T float Print(5.5f); return 0; }模板不仅仅能抽象类型还能抽象编译时可以确定的常量值例如int、bool等#include iostream // 声明一个类模板包含类型参数 T 和整型非类型参数 N templatetypename T, int N class Array { private: T m_Array[N]; // 使用模板参数定义数组 public: int GetSize() const { return N; } }; int main() { // 实例化一个存储 int 类型、大小为 5 的 Array 类 Arrayint, 5 array; std::cout array.GetSize() std::endl; // 输出 5 return 0; }模板非常强大它可以使得大量代码复用但不要为了炫技而滥用。可读性和可维护性永远是第一位的。如果一个模板复杂到需要花几个小时才能理解其行为那它很可能会成为团队的噩梦。

更多文章