一、上期回顾

搞定菱形继承、虚继承,解决多继承二义性与数据冗余,继承板块彻底学完。今天集中补齐 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) 
    {

    }
};

极易出现未定义行为,开发尽量按声明顺序写初始化列表。


七、今日核心总结

  1. explicit:禁止单参构造隐式转换,工程必加
  2. 友元函数:全局函数访问类私有成员
  3. 友元类:整个类拥有访问权限,破坏封装,慎用
  4. namespace:解决命名冲突,支持嵌套、三种引入方式
  5. 成员初始化顺序由类内声明顺序决定,与初始化列表无关

八、课后练习

  1. 给单参构造加 explicit,测试隐式转换是否报错
  2. 手写友元函数,直接访问类私有成员
  3. 自定义命名空间,隔离自己的函数和变量

更多推荐