一、上期回顾
搞定菱形继承、虚继承,解决多继承二义性与数据冗余,继承板块彻底学完。今天集中补齐C++ 剩余高频语法细节:explicit 关键字、友元函数 / 友元类、命名空间深度、成员初始化细节,收尾 C++ 基础语法全部重难点。
二、explicit 关键字
作用
禁止单参构造函数隐式类型转换
无 explicit 隐式转换坑点
class Person { public: Person(int age) { cout << "有参构造" << endl; } }; int main() { // 隐式转换:int 自动转 Person 对象 Person p = 18; return 0; }编译器偷偷把18隐式构造出临时对象,容易引发诡异 bug。
加 explicit 禁止隐式转换
class Person { public: explicit Person(int age) { cout << "有参构造" << endl; } }; int main() { // 报错,禁止隐式转换 // Person p = 18; // 只能显式调用 Person p(18); return 0; }工程规范:单参构造一律加explicit,杜绝隐式转换。
三、友元函数
作用
让全局函数可以直接访问类的private私有成员
语法
类内声明friend,类外实现普通函数
#include <iostream> using namespace std; class Point { private: int x, y; // 声明友元 friend void printPoint(const Point& p); public: Point(int a, int b) : x(a), y(b) {} }; // 全局友元函数 void printPoint(const Point& p) { // 直接访问私有成员 cout << p.x << " " << p.y << endl; } int main() { Point p(10,20); printPoint(p); return 0; }四、友元类
一个类可以成为另一个类的友元,全部成员函数都能访问对方私有成员行
class A { // 声明B是A的友元类 friend class B; private: int num = 100; }; class B { public: void show(A a) { // 直接访问A私有成员 cout << a.num << endl; } };友元缺点
破坏封装性,尽量少用,仅运算符重载、少量特殊场景使用。
五、命名空间 namespace 深度
解决问题
大型项目全局命名冲突,隔离代码域
1. 定义命名空间
namespace MyCode { int val = 666; void func() { cout << "命名空间函数" << endl; } }2. 三种使用方式
// 方式1:作用域访问 MyCode::val; // 方式2:引入单个成员 using MyCode::func; // 方式3:引入整个命名空间 using namespace MyCode;3. 命名空间嵌套
namespace A { namespace B { int x = 10; } } // 使用:A::B::x六、类内成员初始化陷阱
1. 初始化列表优先于构造函数赋值
2. 初始化顺序只看类内声明顺序,和初始化列表顺序无关
class Test { private: int a; int b; public: // 先初始化a,再b,不是按列表顺序 Test(int x) : b(x), a(b) { } };极易出现未定义行为,开发尽量按声明顺序写初始化列表。
七、今日核心总结
- explicit:禁止单参构造隐式转换,工程必加
- 友元函数:全局函数访问类私有成员
- 友元类:整个类拥有访问权限,破坏封装,慎用
- namespace:解决命名冲突,支持嵌套、三种引入方式
- 成员初始化顺序由类内声明顺序决定,与初始化列表无关
八、课后练习
- 给单参构造加 explicit,测试隐式转换是否报错
- 手写友元函数,直接访问类私有成员
- 自定义命名空间,隔离自己的函数和变量