C++带参函数声明与定义需严格一致:类型、数量、顺序、const/volatile修饰必须匹配;声明放头文件,定义放.cpp;大对象优先用const T&避免拷贝;默认参数仅声明中指定且右连续;引用类型决定实参绑定规则。

怎么写带参数的 C++ 函数声明和定义
函数声明和定义必须参数类型、数量、顺序完全一致,否则链接失败或调用错乱。void print_message(std::string msg, int times) 声明后,定义里不能漏掉 std::string 的命名空间,也不能把 int times 写成 const int t —— 参数名可以不同,但类型和 const/volatile 修饰必须匹配。
常见错误现象:undefined reference to 'print_message(std::string, int)',往往是因为声明用了 std::string,定义却只写了 string(没加 using namespace std 或没引入头文件),或者声明在头文件里,定义时忘了加 inline 或放在了 .cpp 里但没正确链接。
- 声明通常放头文件(
.h或.hpp),定义放源文件(.cpp);若要内联,定义也得在头文件里,且加inline - 参数类型尽量显式写全:用
const std::string&而非std::string,避免无谓拷贝 - 默认参数只能在声明中指定,定义里不允许再写;且默认参数必须从右往左连续(
int a, int b = 1, int c = 2合法,int a = 0, int b, int c = 2不合法)
值传递、引用传递、指针传递怎么选
传小对象(如 int、char、enum)直接值传递最自然;传大对象(如 std::vector、自定义类)不加 const & 就是性能陷阱。
容易踩的坑:void process(std::vector<int> v)</int> 每次调用都深拷贝整个 vector;而 void process(const std::vector<int>& v)</int> 零拷贝。但如果函数内部要修改原对象,就得去掉 const,或改用指针(std::vector<int>* v</int>),不过指针需额外判空。
立即学习“C++免费学习笔记(深入)”;
- 只读访问大对象 →
const T& - 需要修改原对象 →
T&(调用方必须传变量,不能传字面量或临时对象) - 可选修改 + 允许传
nullptr→T*,但得自己检查有效性 - 移动语义适用场景(如接收临时对象)→
T&&,一般用于构造函数或std::move接收
函数参数里用 auto 和模板推导的区别
auto 不能直接用在普通函数参数里(C++20 前不支持),你写的 void f(auto x) 实际是模板语法糖,等价于 template<typename t> void f(T x)</typename>。它不是运行时类型推导,而是编译期为每种实参类型生成一份函数实例。
性能影响明显:传 int 和 double 会生成两个独立函数,代码体积增大;而普通函数用 double 参数,int 会隐式转成 double,只有一份代码。
- 想泛化且接受不同类型 → 用模板函数,但注意实例膨胀
- 只想统一接口、类型可转换 → 普通函数 + 显式类型更轻量
- C++20 起支持
auto参数,但底层仍是模板,别误以为是动态类型
为什么函数声明里 const 位置会影响调用
参数是否 const 不影响重载决议,但 const 修饰的是形参本身(如 int const x),而非所指对象;真正影响调用的是引用/指针所指内容的 const 性,比如 void f(const std::string& s) 可以接受临时 std::string("hi"),而 void f(std::string& s) 不行——因为非常量左值引用不能绑定到右值。
典型报错:error: cannot bind non-const lvalue reference of type 'std::string&' to an rvalue of type 'std::string'。这不是 const 写错了,是引用类型和实参生命周期不匹配。
-
T&:只接受具名变量(左值),且允许修改 -
const T&:接受左值、右值、字面量,安全通用 -
T&&:专为右值设计,常用于移动或完美转发 - 函数返回局部对象?别返回
T&,那是悬垂引用
参数类型、传递方式、const 修饰三者交织,最容易被忽略的是「临时对象能否绑定」和「头文件与实现分离时的符号可见性」——这两处一出错,编译器报的错往往离真实问题很远。










