Lesson04---类与对象(下篇)

目录

一、再谈构造函数

[1.1 构造函数体赋值](#1.1 构造函数体赋值)

通俗概念

关键注意点

[1.2 初始化列表](#1.2 初始化列表)

通俗概念

初始化列表四大注意点

[1.3 explicit 关键字](#1.3 explicit 关键字)

通俗概念

关键注意点

[二、Static 成员](#二、Static 成员)

[2.1 概念与实战](#2.1 概念与实战)

通俗概念

[2.2 五大特性与常见问题](#2.2 五大特性与常见问题)

静态成员五大核心特性

常见问题

三、友元

[3.1 通俗概念](#3.1 通俗概念)

[3.2 友元函数](#3.2 友元函数)

问题引入

友元函数五大特性

[3.3 友元类](#3.3 友元类)

通俗概念

友元类三大特性

四、内部类

[4.1 通俗概念](#4.1 通俗概念)

[4.2 内部类四大核心特性](#4.2 内部类四大核心特性)

五、匿名对象

[5.1 通俗概念](#5.1 通俗概念)

[5.2 关键注意点](#5.2 关键注意点)

六、拷贝对象时的编译器优化

[6.1 通俗概念](#6.1 通俗概念)

[6.2 编译器优化核心场景](#6.2 编译器优化核心场景)

[6.3 注意点](#6.3 注意点)

七、再次理解封装

[7.1 核心逻辑](#7.1 核心逻辑)

[7.2 现实世界与计算机世界的对应关系](#7.2 现实世界与计算机世界的对应关系)

[7.3 关键理解](#7.3 关键理解)

[八、练习题清单(OJ 实战)](#八、练习题清单(OJ 实战))

九、学习总结与建议


一、再谈构造函数

1.1 构造函数体赋值

通俗概念

构造函数体内的赋值操作,本质是 "赋初值" 而非 "初始化"------ 因为初始化只能进行一次,而构造函数体中可以对成员变量多次赋值。

cpp 复制代码
#include <iostream>
using namespace std;

class Date {
public:
    // 构造函数体赋值(赋初值,可多次赋值)
    Date(int year, int month, int day) {
        _year = year;  // 第一次赋值
        _month = month;
        _day = day;
        _year = 2024;  // 第二次赋值(合法)
    }

    void Print() {
        cout << _year << "-" << _month << "-" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main() {
    Date d(2023, 5, 22);
    d.Print(); // 输出:2024-5-22(第二次赋值覆盖第一次)
    return 0;
}

关键注意点

  • 构造函数体赋值的核心是 "修改已有变量的值",成员变量的初始化(内存分配 + 初始值)在进入函数体前已完成;
  • 对于引用、const、无默认构造的自定义类型成员,无法在构造函数体中 "初始化"(只能赋值,但这些成员必须初始化一次),需用初始化列表。

1.2 初始化列表

通俗概念

初始化列表是构造函数的特殊语法,用于在成员变量初始化阶段直接赋值 (仅执行一次),语法格式:构造函数名(参数) : 成员1(值1), 成员2(值2), ... {}

cpp 复制代码
#include <iostream>
using namespace std;

// 自定义类型A:无默认构造函数(必须传参)
class A {
public:
    A(int a) : _a(a) {
        cout << "A(int a)" << endl;
    }
private:
    int _a;
};

class B {
public:
    // 必须用初始化列表的三种场景:引用、const、无默认构造的自定义类型
    B(int a, int ref_val) 
        : _aobj(a)    // 自定义类型A无默认构造,必须初始化列表
        , _ref(ref_val)// 引用成员必须初始化列表
        , _n(10)       // const成员必须初始化列表
        , _x(20)       // 普通成员也可初始化列表(推荐)
    {
        // _ref = ref_val; // 错误:引用不能赋值,只能初始化
        // _n = 10;       // 错误:const成员不能赋值,只能初始化
        // _aobj = A(a);  // 错误:A无默认构造,无法先默认初始化再赋值
    }

private:
    A _aobj;        // 无默认构造的自定义类型
    int& _ref;      // 引用成员
    const int _n;   // const成员
    int _x;         // 普通成员(推荐初始化列表)
};

// 初始化顺序问题(与声明次序一致,与列表顺序无关)
class C {
public:
    C(int a) 
        : _a1(a)   // 列表顺序1:_a1先写
        , _a2(_a1) // 列表顺序2:_a2后写
    {}

    void Print() {
        cout << "_a1 = " << _a1 << ", _a2 = " << _a2 << endl;
    }

private:
    int _a2; // 声明顺序1:_a2先声明
    int _a1; // 声明顺序2:_a1后声明
};

int main() {
    B b(5, 100); // 输出:A(int a)(_aobj初始化)
    
    C c(1);
    c.Print(); // 输出:_a1 = 1, _a2 = 随机值(_a2先初始化,此时_a1未初始化)
    return 0;
}
cpp 复制代码
A(int a)
_a1 = 1, _a2 = 4199040(随机值)

初始化列表四大注意点

  • 每个成员变量在初始化列表中只能出现一次(初始化仅能一次);
  • 以下成员必须 用初始化列表初始化:
    • 引用成员变量(int& _ref);
    • const 成员变量(const int _n);
    • 无默认构造的自定义类型成员(如 A 类对象_aobj);
  • 无论是否使用初始化列表,自定义类型成员变量都会先通过初始化列表初始化(默认调用其默认构造);
  • 成员变量的初始化顺序 = 类中声明次序 ,与初始化列表中的先后顺序无关(如 C 类中_a2先声明,先初始化)。

1.3 explicit 关键字

通俗概念

explicit修饰单参构造函数(或除第一个参数外其余有默认值的构造函数),可禁止构造函数的隐式类型转换,避免代码可读性问题。

cpp 复制代码
#include <iostream>
using namespace std;

class Date {
public:
    // explicit修饰单参构造函数,禁止隐式转换
    explicit Date(int year) 
        : _year(year)
        , _month(1)
        , _day(1)
    {}

    // 若注释explicit,以下构造函数也支持隐式转换(多参但后两个有默认值)
    // Date(int year, int month = 1, int day = 1)
    //     : _year(year), _month(month), _day(day)
    // {}

    Date& operator=(const Date& d) {
        if (this != &d) {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;
    }

    void Print() {
        cout << _year << "-" << _month << "-" << _day << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

void Test() {
    Date d1(2022);
    d1.Print(); // 输出:2022-1-1

    // 隐式转换:用int 2023构造无名Date对象,再赋值给d1
    // 若Date构造函数加explicit,此行编译报错;否则合法
    // d1 = 2023; 

    // 显式转换(强制类型转换,即使加explicit也合法)
    d1 = Date(2023);
    d1.Print(); // 输出:2023-1-1
}

int main() {
    Test();
    return 0;
}

关键注意点

  1. explicit仅修饰构造函数,作用是禁止 "用其他类型隐式转换为当前类对象";
  2. 单参构造函数(如Date(int year))或 "首参无默认值、其余有默认值" 的多参构造函数(如Date(int year, int month=1, int day=1)),默认支持隐式转换;
  3. 隐式转换的本质:d1 = 2023 → 编译器自动构造Date(2023)临时对象 → 调用赋值重载给 d1 赋值;
  4. 开发建议:单参构造函数尽量加explicit,避免无意识的隐式转换导致代码可读性下降。

面试小提示

常考:"初始化列表和构造函数体赋值的区别?"------ 答:1. 初始化时机:初始化列表在成员变量初始化阶段执行(仅一次),构造函数体在初始化后执行(可多次赋值);2. 适用场景:引用、const、无默认构造的自定义类型必须用初始化列表;3. 效率:初始化列表更高效(避免默认初始化 + 赋值的双重操作)。


二、Static 成员

2.1 概念与实战

通俗概念

static修饰的类成员(变量 / 函数),属于整个类而非某个对象,所有对象共享该成员,存储在静态区(不在对象内存中)。

核心实战(面试题:统计对象创建个数)

cpp 复制代码
#include <iostream>
using namespace std;

class A {
public:
    // 构造函数:创建对象时计数+1
    A() { ++_scount; }
    // 拷贝构造函数:拷贝对象时计数+1
    A(const A& t) { ++_scount; }
    // 析构函数:对象销毁时计数-1
    ~A() { --_scount; }

    // 静态成员函数:访问静态成员变量(无this指针)
    static int GetACount() { return _scount; }

private:
    // 静态成员变量:类内声明,类外初始化
    static int _scount;
};

// 静态成员变量类外初始化(不加static关键字)
int A::_scount = 0;

void TestA() {
    // 未创建对象时,计数为0(通过类名访问静态成员函数)
    cout << "未创建对象:" << A::GetACount() << endl; // 输出0

    A a1, a2; // 构造2个对象,计数=2
    A a3(a1); // 拷贝构造1个对象,计数=3
    cout << "创建3个对象:" << A::GetACount() << endl; // 输出3

    // 也可通过对象访问静态成员函数(不推荐,静态成员不属于对象)
    cout << "通过对象访问:" << a1.GetACount() << endl; // 输出3
}

int main() {
    TestA();
    // TestA函数结束,对象销毁,计数=0
    cout << "函数结束后:" << A::GetACount() << endl; // 输出0
    return 0;
}
cpp 复制代码
未创建对象:0
创建3个对象:3
通过对象访问:3
函数结束后:0

2.2 五大特性与常见问题

静态成员五大核心特性
  1. 共享性:静态成员为所有类对象共享,不属于某个具体对象;
  2. 初始化:静态成员变量必须在类外定义 (类内仅声明),定义时不加static
  3. 访问方式:支持类名::静态成员(推荐)或对象.静态成员(不推荐);
  4. 无 this 指针:静态成员函数没有隐藏的 this 指针,不能访问任何非静态成员(变量 / 函数);
  5. 访问权限:受public/protected/private限定符控制(如 private 静态成员,类外无法访问)。
常见问题
  1. 静态成员函数可以调用非静态成员函数吗?答:不能。静态成员函数无 this 指针,无法访问非静态成员(非静态成员依赖具体对象)。
  2. 非静态成员函数可以调用静态成员函数吗?答:可以。静态成员属于类,全局唯一,非静态成员函数可通过类名或隐含访问。

面试小提示

静态成员是高频考点!常考场景:统计对象个数、实现单例模式、共享配置参数等。核心记住 "无 this 指针、类外初始化、共享性" 三大关键点。


三、友元

3.1 通俗概念

友元是突破类封装的特殊机制,允许外部函数 / 类直接访问类的私有 / 保护成员,但会增加耦合度,破坏封装,不宜多用。友元分为友元函数友元类

3.2 友元函数

问题引入

重载operator<<(cout 输出)时,若作为成员函数,this 指针会抢占第一个参数位置(左操作数),导致调用形式为d1 << cout(不符合常规cout << d1),需用友元函数解决。

cpp 复制代码
#include <iostream>
using namespace std;

class Date {
    // 声明友元函数:允许operator<<访问私有成员
    friend ostream& operator<<(ostream& _cout, const Date& d);
    // 声明友元函数:允许operator>>访问私有成员
    friend istream& operator>>(istream& _cin, Date& d);

public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}

private:
    int _year;
    int _month;
    int _day;
};

// 友元函数:类外定义,无this指针,可直接访问私有成员
ostream& operator<<(ostream& _cout, const Date& d) {
    _cout << d._year << "-" << d._month << "-" << d._day;
    return _cout; // 返回cout,支持连续输出(cout << d1 << d2)
}

istream& operator>>(istream& _cin, Date& d) {
    _cin >> d._year >> d._month >> d._day;
    return _cin; // 返回cin,支持连续输入(cin >> d1 >> d2)
}

int main() {
    Date d;
    cin >> d; // 调用友元函数operator>>
    cout << d << endl; // 调用友元函数operator<<
    return 0;
}
cpp 复制代码
输入:2024 5 22
2024-5-22

友元函数五大特性

  • 友元函数是类外普通函数,不属于任何类 ,但需在类内声明(加friend关键字);
  • 可直接访问类的私有 / 保护成员,无需通过对象或成员函数;
  • 不能用const修饰(无 this 指针,const 修饰的是 this);
  • 声明位置不受访问限定符限制(public/protected/private 均可);
  • 一个函数可作为多个类的友元函数。

3.3 友元类

通俗概念

若类 B 是类 A 的友元类,则类 B 的所有成员函数都可直接访问类 A 的私有 / 保护成员,但友元关系是单向、不可传递的。

cpp 复制代码
#include <iostream>
using namespace std;

class Time {
    // 声明Date为Time的友元类:Date的所有成员函数可访问Time的私有成员
    friend class Date;

public:
    Time(int hour = 0, int minute = 0, int second = 0)
        : _hour(hour)
        , _minute(minute)
        , _second(second)
    {}

private:
    int _hour;
    int _minute;
    int _second;
};

class Date {
public:
    Date(int year = 1900, int month = 1, int day = 1)
        : _year(year)
        , _month(month)
        , _day(day)
    {}

    // Date的成员函数可直接访问Time的私有成员
    void SetTimeOfDate(int hour, int minute, int second) {
        _t._hour = hour;    // 直接访问Time的私有成员_hour
        _t._minute = minute;// 直接访问Time的私有成员_minute
        _t._second = second;// 直接访问Time的私有成员_second
    }

    void Print() {
        cout << _year << "-" << _month << "-" << _day << " ";
        cout << _t._hour << ":" << _t._minute << ":" << _t._second << endl;
    }

private:
    int _year;
    int _month;
    int _day;
    Time _t; // Time类对象
};

int main() {
    Date d(2024, 5, 22);
    d.SetTimeOfDate(10, 30, 45);
    d.Print(); // 输出:2024-5-22 10:30:45
    return 0;
}

友元类三大特性

  1. 单向性:Time 声明 Date 为友元,Date 可访问 Time 的私有成员,但 Time 不能访问 Date 的私有成员;
  2. 不可传递性:若 C 是 B 的友元,B 是 A 的友元,不能推出 C 是 A 的友元;
  3. 不可继承性:友元关系不能被子类继承(后续继承章节详解)。

面试小提示

常考:"友元的优缺点?"------ 答:优点:突破封装,方便外部函数 / 类访问类的私有成员,简化代码;缺点:增加代码耦合度,破坏封装性,降低代码可维护性,建议少用。


四、内部类

4.1 通俗概念

定义在另一个类内部的类称为内部类,它是独立的类(不属于外部类),但天生是外部类的友元类(可访问外部类的所有成员)。

cpp 复制代码
#include <iostream>
using namespace std;

class A {
private:
    static int _k; // 静态成员变量
    int _h;        // 非静态成员变量

public:
    // 内部类B:独立类,天生是A的友元
    class B {
    public:
        void foo(const A& a) {
            // 可访问A的静态成员(无需A的对象)
            cout << "A::_k = " << _k << endl;
            // 可访问A的非静态成员(需通过A的对象)
            cout << "A::_h = " << a._h << endl;
        }
    };
};

// 外部类A的静态成员变量类外初始化
int A::_k = 10;

int main() {
    // 内部类的访问方式:外部类名::内部类名
    A::B b;
    A a;
    a._h = 20;

    b.foo(a); // 内部类访问外部类成员

    // 外部类大小与内部类无关(内部类是独立类)
    cout << "sizeof(A) = " << sizeof(A) << endl; // 输出4(仅_h的大小)
    cout << "sizeof(A::B) = " << sizeof(A::B) << endl; // 输出1(空类)
    return 0;
}
cpp 复制代码
A::_k = 10
A::_h = 20
sizeof(A) = 4
sizeof(A::B) = 1

4.2 内部类四大核心特性

  • 独立性:内部类是独立类,编译后生成单独的目标文件(如A::B编译为A_B),外部类的对象不包含内部类的成员;
  • 友元关系:内部类天生是外部类的友元,可访问外部类的所有成员(静态成员直接访问,非静态成员需通过外部类对象);
  • 访问限定符:内部类可定义在外部类的 public/protected/private 区域,访问权限受限定符控制(如 private 内部类,类外无法访问);
  • 大小无关:sizeof(外部类)仅计算外部类自身成员的大小,与内部类无关。

五、匿名对象

5.1 通俗概念

匿名对象是无名称的类对象,语法为类名(参数),生命周期仅当前行(行结束后自动调用析构函数),适合临时使用一次的场景

cpp 复制代码
#include <iostream>
using namespace std;

class A {
public:
    A(int a = 0) : _a(a) {
        cout << "A(int a):" << this << endl;
    }

    ~A() {
        cout << "~A():" << this << endl;
    }

    void Show() {
        cout << "A::_a = " << _a << endl;
    }

private:
    int _a;
};

class Solution {
public:
    int Sum_Solution(int n) {
        return n * (n + 1) / 2; // 简化版求和(实际需按OJ要求实现)
    }
};

int main() {
    // 普通对象:生命周期到main函数结束
    A aa1(10);
    aa1.Show();
    cout << "----------------" << endl;

    // 匿名对象:生命周期仅当前行,行结束后析构
    A(20); // 无名称,创建后立即析构
    cout << "----------------" << endl;

    // 匿名对象的实用场景:临时调用成员函数(无需定义命名对象)
    int sum = Solution().Sum_Solution(10); // Solution()是匿名对象
    cout << "1+2+...+10 = " << sum << endl;

    return 0;
}
cpp 复制代码
A(int a):0x7ffee3b558a0
A::_a = 10
----------------
A(int a):0x7ffee3b55890
~A():0x7ffee3b55890
----------------
1+2+...+10 = 55
~A():0x7ffee3b558a0

5.2 关键注意点

  • 匿名对象的声明:A()是匿名对象,A aa()是函数声明(返回 A 类型,无参),避免混淆;
  • 生命周期:匿名对象仅在当前行有效,行结束后自动析构,比命名对象更节省内存(临时使用场景);
  • 实用场景:临时调用成员函数(如 Solution ().Sum_Solution (10))、作为函数参数 / 返回值(配合编译器优化)。

六、拷贝对象时的编译器优化

6.1 通俗概念

编译器在对象传参、传返回值时,会自动优化拷贝构造的次数(如 "连续构造 + 拷贝构造" 优化为 "直接构造"),减少对象拷贝开销。

cpp 复制代码
#include <iostream>
using namespace std;

class A {
public:
    A(int a = 0) : _a(a) {
        cout << "A(int a):" << this << endl;
    }

    A(const A& aa) : _a(aa._a) {
        cout << "A(const A& aa):" << this << endl;
    }

    A& operator=(const A& aa) {
        cout << "A& operator=(const A& aa):" << this << endl;
        if (this != &aa) {
            _a = aa._a;
        }
        return *this;
    }

    ~A() {
        cout << "~A():" << this << endl;
    }

private:
    int _a;
};

// 场景1:传值传参(无优化,拷贝1次)
void f1(A aa) {}

// 场景2:传值返回(编译器优化后,拷贝次数减少)
A f2() {
    A aa(2);
    return aa;
}

int main() {
    cout << "=== 场景1:传值传参 ===" << endl;
    A aa1(1);
    f1(aa1); // 传值,调用拷贝构造
    cout << endl;

    cout << "=== 场景2:传值返回 ===" << endl;
    f2(); // 编译器优化:构造+拷贝构造 → 直接构造(仅1次构造)
    cout << endl;

    cout << "=== 场景3:隐式类型转换(优化) ===" << endl;
    f1(3); // 3→A(3)(构造)+ 拷贝构造 → 优化为直接构造
    cout << endl;

    cout << "=== 场景4:连续拷贝构造(优化) ===" << endl;
    A aa2 = f2(); // f2返回拷贝+aa2拷贝构造 → 优化为1次构造
    cout << endl;

    cout << "=== 场景5:拷贝构造+赋值重载(无优化) ===" << endl;
    aa1 = f2(); // f2返回拷贝(1次)+ 赋值重载(1次)→ 无优化
    cout << endl;

    return 0;
}
cpp 复制代码
=== 场景1:传值传参 ===
A(int a):0x7ffee3b558a0
A(const A& aa):0x7ffee3b55890
~A():0x7ffee3b55890
~A():0x7ffee3b558a0

=== 场景2:传值返回 ===
A(int a):0x7ffee3b55880
~A():0x7ffee3b55880

=== 场景3:隐式类型转换(优化) ===
A(int a):0x7ffee3b55870
~A():0x7ffee3b55870

=== 场景4:连续拷贝构造(优化) ===
A(int a):0x7ffee3b55860

=== 场景5:拷贝构造+赋值重载(无优化) ===
A(int a):0x7ffee3b55850
A(const A& aa):0x7ffee3b55840
A& operator=(const A& aa):0x7ffee3b55860
~A():0x7ffee3b55840
~A():0x7ffee3b55850

~A():0x7ffee3b55860

6.2 编译器优化核心场景

  • 隐式类型转换:f1(3) → 构造A(3)+ 拷贝构造 → 优化为直接构造
  • 连续构造 + 拷贝构造:f1(A(2)) → 构造A(2)+ 拷贝构造 → 优化为直接构造
  • 传值返回 + 拷贝构造:A aa2 = f2() → f2 返回拷贝 + aa2 拷贝构造 → 优化为1 次构造
  • 不可优化场景:aa1 = f2() → 传值返回拷贝 + 赋值重载 → 无优化(两次操作独立)。

6.3 注意点

  • 优化仅在 "同一个表达式中" 生效,跨表达式的拷贝无法优化;
  • 不同编译器优化程度不同(GCC/Clang 优化较彻底,VS 部分场景优化);
  • 开发建议:传参时优先用引用(const A&),减少拷贝;返回值时可利用编译器优化,避免不必要的拷贝。

七、再次理解封装

7.1 核心逻辑

计算机无法直接识别现实世界的实体(如洗衣机、人),需通过 "抽象→描述→实例化" 三步让计算机认识:

  1. 抽象:在思想层面对实体进行认知(如洗衣机有属性:容量、品牌;方法:洗衣、甩干);
  2. 描述:用 C++ 类将抽象结果编码(属性→成员变量,方法→成员函数),形成自定义类型;
  3. 实例化:用类创建具体对象,计算机通过对象模拟现实实体的行为。

7.2 现实世界与计算机世界的对应关系

|--------------------|-------|-------------|
| 现实世界 | 计算机世界 | 核心操作 |
| 实体(洗衣机、人) | 对象 | 实例化(类→对象) |
| 实体的共性(洗衣机的属性 / 方法) | 类 | 抽象(实体→类) |
| 实体的行为(洗衣、计算) | 成员函数 | 调用(对象。成员函数) |
| 实体的特征(容量、年龄) | 成员变量 | 访问(对象。成员变量) |

7.3 关键理解

封装的本质是 "管理访问权限":将实体的属性和方法结合,隐藏内部实现细节(如洗衣机的电机工作原理),仅暴露必要接口(如开机键、洗衣模式),让用户无需关心内部逻辑,只需通过接口交互。


八、练习题清单(OJ 实战)

推荐的 OJ 练习题(便于巩固知识点):

  1. 求 1+2+...+n(禁止使用乘除法、循环、条件判断);https://www.nowcoder.com/practice/7a0da8fc483247ff8800059e12d7caf1?tpId=13&tqId=11200&tPage=3&rp=3&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking
  2. 计算日期到天数的转换(将年 / 月 / 日转换为当年的第几天);https://www.nowcoder.com/practice/769d45d455fe40b385ba32f97e7bcded?tpId=37&&tqId=21296&rp=1&ru=/activity/oj&qru=/ta/huawei/question-ranking
  3. 日期差值(计算两个日期之间的天数差);https://www.nowcoder.com/practice/ccb7383c76fc48d2bbc27a2a6319631c?tpId=62&&tqId=29468&rp=1&ru=/activity/oj&qru=/ta/sju-kaoyan/question-ranking
  4. 打印日期(根据输入的年 / 月,打印该月的日历);https://www.nowcoder.com/practice/b1f7a77416194fd3abd63737cdfcf82b?tpId=69&&tqId=29669&rp=1&ru=/activity/oj&qru=/ta/hust-kaoyan/question-ranking
  5. 累加天数(给定日期和天数,计算累加后的日期)。https://www.nowcoder.com/practice/eebb2983b7bf40408a1360efb33f9e5d?tpId=40&&tqId=31013&rp=1&ru=/activity/oj&qru=/ta/kaoyan/question-ranking

提示:这些题目均为类与对象的实战场景,需结合日期类、构造函数、运算符重载等知识点实现,建议逐一完成,加深理解。


九、学习总结与建议

  • 核心逻辑:本章围绕 "类的进阶特性" 展开,重点是突破基础语法,掌握构造函数优化、静态成员、友元、内部类等高级用法,同时理解编译器对拷贝的优化机制;
  • 重点突破:
    • 初始化列表:必须掌握三种强制场景和初始化顺序问题;
    • static 成员:无 this 指针、类外初始化、共享性三大核心;
    • 友元:友元函数(重载 <<>>)和友元类(单向 / 不可传递);
    • 编译器优化:常见优化场景,减少拷贝开销;
  • 学习方法:
    • 多敲代码:重点测试初始化列表、友元、匿名对象的生命周期;
    • 对比记忆:构造函数体赋值 vs 初始化列表、静态成员 vs 非静态成员、友元 vs 封装;
    • 实战巩固:完成 OJ 练习题,将知识点落地到代码;
  • 避坑清单:
    • 初始化列表的顺序与声明顺序一致,与列表顺序无关;
    • 静态成员变量必须类外初始化,不加 static;
    • 友元关系是单向的,不可传递、不可继承;
    • 匿名对象A()与函数声明A aa()的区别;
    • explicit 禁止单参构造函数的隐式转换,提升代码可读性。

相关推荐
毕设源码-朱学姐2 小时前
【开题答辩全过程】以 基于Java的九价疫苗预约系统为例,包含答辩的问题和答案
java·开发语言
雨季6662 小时前
Flutter 三端应用实战:OpenHarmony “微光笔记”——在灵感消逝前,为思想点一盏灯
开发语言·javascript·flutter·ui·dart
yugi9878382 小时前
遗传算法优化的极限学习机模型(GA-ELM)Matlab实现
开发语言·matlab
梦梦代码精2 小时前
开源、免费、可商用:BuildingAI一站式体验报告
开发语言·前端·数据结构·人工智能·后端·开源·知识图谱
郝学胜-神的一滴2 小时前
Linux网络编程之listen函数:深入解析与应用实践
linux·服务器·开发语言·网络·c++·程序人生
焱童鞋2 小时前
解决 MeteoInfoLab 3.9.11 中 contourfm 导致的 ArrayIndexOutOfBoundsException
开发语言·python
lzhdim2 小时前
C#开发的提示显示例子 - 开源研究系列文章
开发语言·c#
有代理ip2 小时前
成功请求的密码:HTTP 2 开头响应码深度解析
java·大数据·python·算法·php