c++项目

typedef

typedef T value_type;语法的结构是typedef 原类型 新别名;定义后,value_type 和 T 就是同一个类型,可以互换使用

模板

C++ 模板的声明和定义分离有特殊性,和普通函数/类不一样

  1. 普通函数可以分离
cpp 复制代码
// 头文件 add.h
int add(int a, int b);  // 声明

// 源文件 add.cpp
int add(int a, int b) {  // 定义
    return a + b;
}

// main.cpp 可以正常使用
#include "add.h"
int main() {
    add(1, 2);  // 链接时找到定义
}
  1. 模板不能这样分离
cpp 复制代码
// 头文件 add.h
template <typename T>
T add(T a, T b);  // 声明

// 源文件 add.cpp
template <typename T>
T add(T a, T b) {  // 定义
    return a + b;
}

// main.cpp - 链接错误!
#include "add.h"
int main() {
    add(1, 2);  // 错误:找不到定义
}

原因:编译器看到 add(1, 2) 时需要生成 add(int, int) 的代码,但定义在 .cpp 文件中看不到

解决方案一:全部放在头文件(最常用)

cpp 复制代码
// add.h - 声明和定义都在头文件
template <typename T>
T add(T a, T b);  // 声明

template <typename T>
T add(T a, T b) {  // 定义
    return a + b;
}

// main.cpp - 正常使用
#include "add.h"
int main() {
    add(1, 2);  // 正确
}

解决方案二:显式实例化(放 .cpp)

cpp 复制代码
// add.h
template <typename T>
T add(T a, T b);  // 只声明

// add.cpp
template <typename T>
T add(T a, T b) {  // 定义
    return a + b;
}

// 显式实例化 - 告诉编译器要生成哪些版本
template int add<int>(int, int);
template double add<double>(double, double);

// main.cpp
#include "add.h"
int main() {
    add(1, 2);      // 可以用,因为 int 版本已生成
    add(1.5, 2.5);  // 可以用,因为 double 版本已生成
    // add("a", "b"); // 错误!没有生成 string 版本
}

类的声明和定义分离

cpp 复制代码
// Box.h
template <typename T>
class Box {
public:
    Box(T val);
    T get();
};

// Box.cpp
template <typename T>
Box<T>::Box(T val) : data(val) {}  // 定义

template <typename T>
T Box<T>::get() { return data; }   // 定义

// main.cpp - 链接错误!

正确做法一:全放头文件

cpp 复制代码
// Box.h
template <typename T>
class Box {
    T data;
public:
    Box(T val) : data(val) {}  // 直接定义
    T get() { return data; }   // 直接定义
};

正确做法二:头文件包含实现文件

cpp 复制代码
// Box.h
template <typename T>
class Box {
    T data;
public:
    Box(T val);
    T get();
};

#include "Box.tpp"  // 包含实现文件

// Box.tpp(实现文件)
template <typename T>
Box<T>::Box(T val) : data(val) {}

template <typename T>
T Box<T>::get() { return data; }

正确做法三:显式实例化

cpp 复制代码
// Box.h
template <typename T>
class Box {
    T data;
public:
    Box(T val);
    T get();
};

// Box.cpp
template <typename T>
Box<T>::Box(T val) : data(val) {}

template <typename T>
T Box<T>::get() { return data; }

// 显式实例化
template class Box<int>;
template class Box<double>;

// main.cpp
#include "Box.h"
int main() {
    Box<int> b1(10);      // 可以用
    Box<double> b2(3.14); // 可以用
    // Box<string> b3("x"); // 错误!没有显式实例化
}

\[\]重载

cpp 复制代码
template <typename T>
class MyVector {
    T* data_;
    
public:
    T& operator[](size_t i) {
        return data_[i];  // 返回引用,不是副本
    }
};

int main() {
    MyVector<int> vec;
    // 假设 data_ 指向 [1, 2, 3, ...]
    
    // 这行代码发生了什么:
    vec[0] = 10;
    
    // 分解步骤:
    // 1. vec[0] 调用 operator[](0)
    // 2. operator[](0) 返回 data_[0] 的引用(不是副本)
    // 3. 给这个引用赋值 = 10
    // 4. 相当于直接修改 data_[0] = 10
}

常量

  1. 常量指针(const pointer)
    指针本身是常量,不能改变指向,但可以修改指向的值
cpp 复制代码
int x = 10;
int y = 20;

int* const p = &x;  // 常量指针:p 本身是 const

*p = 30;    // 正确!可以修改指向的值(x 变成 30)
// p = &y;  // 错误!不能改变指针的指向

// 记忆:const 在 * 后面,修饰 p(指针本身)
  1. 指针常量(pointer to const)
    指针指向的值是常量,不能通过指针修改值,但可以改变指向
cpp 复制代码
int x = 10;
int y = 20;

const int* p = &x;  // 指针常量:指向的值是 const

// *p = 30;  // 错误!不能通过 p 修改 x
p = &y;      // 正确!可以改变指针的指向

// 记忆:const 在 * 前面,修饰 *p(指向的值)
  1. 引用(没有"引用常量")
    引用本身就不能改变指向,所以:
cpp 复制代码
int x = 10;
int y = 20;

int& ref = x;  // 普通引用
ref = y;       // 这是给 x 赋值,不是改变 ref 的指向!

// 引用一旦绑定,就不能重新绑定
// 所以没有"引用常量"这种说法
  1. 常量引用(reference to const)
    通过引用不能修改值
cpp 复制代码
int x = 10;

const int& ref = x;  // 常量引用

// ref = 30;  // 错误!不能通过 ref 修改 x
int y = ref;  // 正确!可以读取

// 没有 int& const ref = x; 这种写法(引用本身就不能改)

记忆技巧

cpp 复制代码
// 从右往左读
int* const p;        // p is a const pointer to int
const int* p;        // p is a pointer to const int
const int* const p;  // p is a const pointer to const int
const int& ref;      // ref is a reference to const int

class 里面定义 struct

class 里面可以定义 struct,默认是 public 的。也可以定义 class(默认 private)

typedef

typedef typename CHxAllocator::template rebind::other NodeAlloc;

原类型:CHxAllocator::template rebind::other(很长的一串)

新类型(别名):NodeAlloc

意思:给 CHxAllocator::template rebind::other 这个类型起个简单的名字叫 NodeAlloc。

CHxAllocator::template rebind::other

CHxAllocator - 一个分配器类型

::rebind - 访问里面的 rebind 模板

::other - 访问 rebind 里的 other 类型

::

:: 是作用域解析运算符,用于访问类、命名空间、结构体等作用域里的成员。

cpp 复制代码
namespace MyNamespace {
    int x = 10;
}

class MyClass {
public:
    typedef int value_type;  // 类型成员
    static int count;        // 静态成员
    
    struct Inner {
        int y;
    };
};

int main() {
    // 命名空间
    MyNamespace::x = 20;
    
    // 类的类型成员
    MyClass::value_type val = 10;
    
    // 类的静态成员
    MyClass::count = 5;
    
    // 类里的结构体
    MyClass::Inner inner;
    inner.y = 30;
}

throw std::bad_alloc(0);

cpp 复制代码
throw 异常对象;  // 抛出异常

// std::bad_alloc 是标准库的异常类
// std::bad_alloc(0) 是创建一个 bad_alloc 对象
// throw 把这个异常抛出去
相关推荐
学习星球18 分钟前
空天地一体化网络(NTN)深度解析:从Starlink D2C到3GPP NTN,卫星直连手机是如何实现的?
网络·人工智能·算法·智能手机·php
小蒜学长21 分钟前
基于SpringBoot + Vue的智能健身房管理系统的设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
DolitD22 分钟前
云流技术深度剖析:单服务器下如何实现3D应用的多实例并发?
java·服务器·前端·3d·云原生·云计算
jun_bai27 分钟前
Ecplise中发布项目到配置的tomcat中
java·服务器
liangbo727 分钟前
JVM规范第 6 章:Java 虚拟机指令集
java·jvm
科技林总29 分钟前
提示词测评落地全流程
人工智能·算法
南城以南溫暖如初14732 分钟前
AI 智能商城 APP 定制开发的核心需求
java·人工智能·spring boot·mysql·mybatis·需求分析
摇滚侠33 分钟前
《SpringBoot 3:入门与应用实战》第 9 章 使用 WebMvc 开发应用 阅读笔记 21
java·spring boot·笔记
Sam_Deep_Thinking39 分钟前
聊聊开闭原则,以及它在Spring里的样子
java·后端·spring·程序员·开闭原则