类的成员函数为什么需要在类外定义
1.1 代码组织与可读性
类内定义:适合 短小简单的函数(如 getter/setter),能直观体现类的接口设计。
类外定义:当函数体较复杂时,将实现移到类外(如 .cpp 文件)可保持 类声明简洁,便于快速理解类的核心接口,避免代码臃肿。
1.2 编译依赖与构建速度
类内定义:若函数体直接写在头文件中,每次修改函数逻辑时,所有包含该头文件的代码都需要重新编译,导致 编译时间大幅增加。
类外定义:将实现放在 .cpp 文件中,修改实现时仅需重新编译该 .cpp 文件,显著提升大型项目的 构建效率。
1.3 避免重复定义(ODR 规则)
类内定义:若头文件被多个源文件包含,类内定义的成员函数会被视为 内联函数(inline)。虽然内联允许重复定义,但过度使用可能导致 代码膨胀。
类外定义:在 .cpp 文件中定义函数,确保 仅有一份实现,严格遵循单一定义规则(One Definition Rule, ODR)。
1.4 封装与信息隐藏
类外定义:可将实现细节隐藏在 .cpp 文件中,仅通过头文件暴露接口。这种方式 减少头文件暴露的内部信息,增强代码的封装性。
2.类内成员函数是否需要同时实现const版本和非const版本
2.1 非const对象可以调用const修饰的成员函数,但是const对象只能调用const成员变量
2.2 当const函数与非const函数代码逻辑几乎相同时
若两个版本的函数逻辑几乎相同(仅返回类型或对象 const 属性不同),可通过 复用代码减少冗余
1.非const函数调用const函数
cpp
class MyArray {
public:
// const 版本实现核心逻辑
const int& operator[](size_t index) const {
// 复杂逻辑(如边界检查)
return data[index];
}
// 非 const 版本复用 const 版本,用 const_cast 移除返回类型的 const
int& operator[](size_t index) {
return const_cast<int&>(
static_cast<const MyArray&>(*this)[index]
);
}
};
1.通过static_cast<const MyArray&>调用operator.[],如果返回值类型一个是const可通过const_cast<int&>进行类型转换
2.万能引用
cpp
class MyArray {
private:
template <typename Self>
static auto& get_element(Self&& self, size_t index) {
// 复杂逻辑(如边界检查)
return self.data[index];
}
public:
int& operator[](size_t index) {
return get_element(*this, index);
}
const int& operator[](size_t index) const {
return get_element(*this, index);
}
};
.*运算符
cpp
class A
{
public:
void func()
{
cout << "A::func()" << endl;
}
};
//typedef void(A::*PF)(); //成员函数指针类型
using PF = void(A::*)();
int main()
{
// C++规定成员函数要加&才能取到函数指针
PF function = &A::func;
A aa;
(aa.*function)();
}
初始化列表初始化引用的问题
cpp
class Myclass {
public:
Myclass(int x):_x(x)
{}
private:
int& _x;
};
int main()
{
Myclass a(1);
return 0;
}
非const引用引用临时变量,编译器仅检查 直接引用绑定 的合法性(如 int& r = 1; 会报错),但无法追踪间接的悬垂引用风险。但是可以传字面量,但是成员变量是const int&,这样就可以延长生命周期,但最好将参数改为与成员变量相同的形参,如int &成员初始化传参就传int&,这样传字面量编译器也会警告