【C++进阶】Cyber骇客的赛博血统上传——【面向对象之 继承 】一文带你搞懂面向对象编程的三要素之————继承

⚡ CYBER_PROFILE ⚡
/// SYSTEM READY ///


WARNING : DETECTING HIGH ENERGY

🌊 🌉 🌊 心手合一 · 水到渠成

|------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------|
| >>> ACCESS TERMINAL <<< ||
| 🦾 作者主页 | 🔥 C语言核心 |
| 💾 编程百度 | 📡 代码仓库 |


Running Process: 100% | Latency: 0ms


索引与导读

1. 继承的核心概念

C++中,继承是面向对象编程(OOP)三大基石之一(封装、继承、多态)

  • 基类 (Base Class / Parent Class):被继承的类,包含通用的属性和方法。

  • 派生类 (Derived Class / Child Class):继承基类的类,可以添加新成员或修改(重写)基类的行为。


2. 继承的基本语法

cpp 复制代码
class Base { /* ... */ };
class Derived : [继承方式] Base { /* ... */ };

2)继承方式(权限继承矩阵表)

无论哪种继承方式,基类的 private 成员在派生类中永远不可见(不可直接访问)

  • 继承方式改变的是基类的 publicprotected 成员在派生类中的"降级"规则:
继承方式 基类成员访问级别 在派生类中的访问级别
public 继承 public 保持为 public
protected 保持为 protected
private 不可见(存在但无法直接访问)
protected 继承 public 降级为 protected
protected 降级为 protected
private 不可见(存在但无法直接访问)
private 继承 public 降级为 private
protected 降级为 private
private 不可见(存在但无法直接访问)

3. 继承与模板的结合

3.1)类 继承 类模板

基类是一个模板,但派生类是一个普通的类

  • 核心逻辑: 在继承时,你必须给基类添加具体的类型(实例化)
cpp 复制代码
template <typename T>
class Base {
public:
    T data;
    void print() { cout << "Base" << endl; }
};

// 派生类是普通类,但必须把基类模板的具体类型写死(比如 int)
class Derived : public Base<int> {
public:
    void doSomething() {
        data = 10; // 这里的 data 已经被确定为 int 类型
        print();
    }
};

总结: 编译器把 Base 当作一个已经完全确定的类来对待


3.2)类模板 继承 类模板

  • 核心逻辑: 派生类本身也是一个模板。派生类需要接收类型参数,并且通常要把这个参数继续传递给基类
cpp 复制代码
template <typename T>
class Base {
public:
    T value;
};

template <typename T>
class Derived :public Base<T> {
public:
    T getValue() {
        return this->value; // 稍后解释为什么这里推荐加 this->
    }
};

Derived<double> d;

return this->value; ------------ 稍后解释为什么这里推荐加 this->


3.3)模板继承的语法坑

在普通的继承中 ,子类可以直接使用父类的 public 和 protected 成员

但在模板继承中,如果你直接使用父类的成员变量或函数,编译器会无情地报错:"找不到该标识符"!

cpp 复制代码
template <typename T>
class Base {
public:
    void foo() {}
};

template <typename T>
class Derived : public Base<T> {
public:
    void bar() {
        foo(); // ❌ 编译报错!找不到 foo()!
    }
};

为什么会这样?(底层原理)
C++ 编译器在解析模板时使用两阶段名字查找

  1. 第一阶段(定义时) :编译器检查模板的语法。此时,它不知道 T 是什么,因此它也不知道 Base<T> 到底是个什么东西(因为你以后可能会写一个针对特定类型的模板特化,而那个特化版本里可能根本没有 foo() 函数)。所以,编译器拒绝去 Base<T> 里查找名字

  2. 第二阶段(实例化时) :只有当你真正写出 Derived<int> d; 时,编译器才开始把具体的类型代入


如何破解?(三大解法)

为了在第一阶段安抚编译器,你需要显式地告诉编译器:"这个名字不是凭空出现的,它依赖于模板参数,去父类里找!"

  1. 使用 this->(最推荐、最优雅):
cpp 复制代码
void bar() { this->foo(); } // 告诉编译器,foo 是属于当前对象(派生自 Base<T>)的成员函数
  1. 使用 Base<T>:: 作用域解析:
cpp 复制代码
void bar() { Base<T>::foo(); } // 显式指明是从父类来的
// ▲ 警告:如果 foo() 是虚函数,这种写法会关闭多态机制(静态绑定),要小心使用!
  1. 使用 using 声明
cpp 复制代码
using Base<T>::foo;
void bar() { foo(); }

4. 基类 和 派生类 之间的转换

  • 我们先定义一个基础的继承体系,作为后面所有代码的演示平台:
cpp 复制代码
#include <iostream>
#include <string>
using namespace std;

// 基类
class Base {
public:
    int base_data = 10;
    virtual ~Base() = default; // 为了支持后面的 dynamic_cast
};

// 派生类
class Derived : public Base {
public:
    int derived_data = 20;
};

virtual ~Base() = default;

只要你的类打算被别人继承,它的析构函数就必须是 virtual
这个我们后期会讲虚函数的作用


4.1)普通类型转换:必须加 const

cpp 复制代码
int a = 1;
    // double& d = a; // ❌ 编译报错!
    const double& d = a; // ✅ 正确。因为 int 转 double 会生成一个匿名的 double 临时变量(右值)

临时变量为常量


4.2)继承体系的特殊处理:不需要 const

cpp 复制代码
Derived derived_obj;
    
    // ✅ 正确且安全!没有产生任何临时对象!
    Base& base_ref = derived_obj; 
    Base* base_ptr = &derived_obj; 

    // 验证:它们操作的是同一块内存
    base_ref.base_data = 999;
    cout << derived_obj.base_data << endl; // 输出 999

当编译器看到 Base& = derived_obj 时,它没有去创建一个新的 Base 临时对象。它只是在底层做了一个指针偏移,让 base_ref 直接指向 derived_obj 内存布局中属于 Base 的那一部分 。既然直接指向了原对象,当然可以直接修改,不需要 const 限制。


4.3)对象切片

cpp 复制代码
void test_object_slicing() {
    Derived d;
    d.base_data = 100;
    d.derived_data = 200;

    // ⚠️ 发生对象切片!这里调用的是 Base::Base(const Base& other)
    Base b = d; 

    cout << b.base_data << endl; // 输出 100,基类数据被成功拷贝
    // cout << b.derived_data << endl; // ❌ 编译报错!b 对象里根本没有 derived_data
}

按值赋值

  • Base b = d;迫使编译器调用Base的拷贝构造函数
  • Base的拷贝构造函数只认识Base自己的成员变量(base_data
  • 它对 Derived 特有的 derived_data 视而不见

4.4)基类绝对不能赋值给派生类

cpp 复制代码
void test_base_to_derived_assignment() {
    Base b;
    
    // Derived d = b; // ❌ 编译直接报错!不允许这种操作!
}

4.5)向下转型的安全隐患与 RTTI

  • 披着 Base 外衣的 Derived
cpp 复制代码
Base* true_derived = new Derived();
  • 纯正的Base
cpp 复制代码
Base* pure_base = new Base();

1)强制类型转换(极其危险)

cpp 复制代码
Derived* p1 = (Derived*)pure_base;

p1->derived_data = 10; ------------>编译通过,但运行时极其容易错误,因为内存里根本没有derived_data

2)安全的向下转型(dynamic_cast 安全转换)

cpp 复制代码
Derived* unsafe_ptr = dynamic_cast<Derived*>(pure_base);
if (unsafe_ptr == nullptr) {
	cout << "转换失败!被 RTTI 拦截,安全着陆。" << endl;
}

pure_base本体就是个 Base

总结

当使用 dynamic_cast 时,C++ 运行时系统会去查询对象虚函数表(vtable)旁的 type_info 信息(这就是 RTTI


5. 继承中的作用域

5.1)基类和派生类都有独立的作用域

C++ 编译器的眼里,全局作用域是最外层,基类作用域在里面,派生类作用域在最里面
编译器找名字的顺序:先在 领地 B 找 -> 找不到再去 领地 A 找 -> 再找不到去全局找

cpp 复制代码
class Base {
    // 领地 A:Base 的作用域
};

class Derived : public Base {
    // 领地 B:Derived 的作用域
};

5.2)同名成员的"隐藏"与 基类:: 显式访问

因为编译器找名字是从内向外找(先找派生类,再找基类)

一旦在派生类的作用域里找到了你要的名字,它就会立刻停止搜索。

这就导致基类里那个同名的成员被"屏蔽"了

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

class Base {
public:
    int value = 100; // 基类的 value
};

class Derived : public Base {
public:
    int value = 200; // 派生类的 value,名字相同,触发隐藏!

    void print() {
        // 1. 直接访问,编译器在当前作用域找到了 value,直接用
        cout << "直接访问 value: " << value << endl; // 输出 200

        // 2. 破除隐藏:必须加上域作用限定符 Base::
        cout << "显式访问 Base::value: " << Base::value << endl; // 输出 100
    }
};

5.3)基类与派生类中关于 函数重载 的潜规则

由于基类和派生类是两个独立的作用域,所以在派生类中只要写了一个同名函数,不管参数列表是什么,基类中所有的同名函数都会被瞬间"秒杀"(隐藏),对派生类对象不再直接可见

  • 我们先定义一个基类
cpp 复制代码
class Base {
public:
    void func() { cout << "Base 的无参 func()" << endl; }
    void func(int x) { cout << "Base 的带参 func(int)" << endl; }
};
  • 再定义一个派生类
cpp 复制代码
class Derived : public Base {
public:
    // 只要名字叫 func,基类里的所有 func 统统被屏蔽!
    void func(string s) { cout << "Derived 的 func(string)" << endl; }
};
  • 接着我们测试
cpp 复制代码
void test_function_hiding() {
	Derived d;

❌ 编译报错!找不到无参的 func,因为被隐藏了

cpp 复制代码
d.func();

❌ 编译报错!找不到接受 int 的 func,即使你传了 10,它也只认 string 版本的

cpp 复制代码
d.func(10);

✅ 成功调用 Derived 的版本

cpp 复制代码
d.func("hello");

破除隐藏的唯一方法:指名道姓

cpp 复制代码
d.Base::func();
d.Base::func(10);

6. 派生类的默认成员函数

默认成员函数通常会有6个
但是我们通常只关注前四个:构造函数、析构函数、拷贝构造函数、赋值重载


6.1)❗我们写这几个默认成员函数,首先思考几个原则性的问题

  1. 我们不写,默认生成的函数行为是什么?是否符合要求?
  2. 不符合,我们要自己实现吗?如何实现?

问题1:

  • 默认行为(编译器的铁律):编译器为你生成的默认函数,对待这两部分有不同的策略。
  • 对待基类部分:无条件调用基类对应的默认函数(默认构造、默认析构、拷贝构造函数、赋值重载)。
  • 对待派生类自己的成员
    • 对于内置类型(int,指针,char 等):构造时不初始化(随机值);拷贝/赋值时进行无脑的字节拷贝(浅拷贝);析构时不作任何处理。
    • 对于自定义类型(如 std::string):调用它们自己的默认函数。
  • 是否符合要求?(分水岭)
    • 符合 :如果你的派生类里只有普通的 int,或者像 std::string 这种自己会管理内存的智能对象,编译器的默认行为堪称完美,你千万不要自己手写。
    • 不符合(灾难降临) :如果你的派生类里有裸指针 ,并且在堆区 new 了一块内存(比如 int* arr = new int[100])。默认的"浅拷贝"会让两个对象的指针指向同一块内存,析构时会导致 Double Free (重复释放内存)导致程序直接崩溃

问题2

  • 结论 :必须自己实现(遵守 C++ 的 Rule of Three / Rule of Five:析构、拷贝构造、赋值重载,要写就一起写)。
  • 如何实现的"生死线" :在你自己手写派生类的这些函数时,你必须显式地去处理"基类部分"!如果你忘了,编译器绝不会帮你填坑,它会给你塞一个默认的过去,导致极其隐蔽的 Bug。

6.2)代码级剖析

假设我们有这样一个场景:基类 Person,派生类 Student

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

class Person {
protected:
    int m_age;
public:
    Person(int age = 0) : m_age(age) { cout << "Person 构造" << endl; }
    Person(const Person& p) : m_age(p.m_age) { cout << "Person 拷贝构造" << endl; }
    Person& operator=(const Person& p) {
        if (this != &p) m_age = p.m_age;
        cout << "Person 赋值" << endl;
        return *this;
    }
    virtual ~Person() { cout << "Person 析构" << endl; }
};

接下来,我们手撕Student的四大默认函数

  1. 派生类的构造函数(先造老子,再造儿子)
  • 如何实现: 必须在派生类的初始化列表中,显式调用基类的构造函数来初始化基类部分
    如果你不写,编译器会强行调用基类的无参默认构造函数(如果基类没有无参构造,直接编译报错)
cpp 复制代码
class Student : public Person {
private:
    char* m_name;
public:
    // ✅ 正确姿势:通过初始化列表,把 age 传给 Person,同时初始化自己的 m_name
    Student(int age, const char* name) : Person(age) {
        m_name = new char[strlen(name) + 1];
        strcpy(m_name, name);
        cout << "Student 构造" << endl;
    }
};

  1. 派生类的拷贝构造函数
  • 如何实现: 很多人自己写深拷贝时,光顾着拷贝自己的指针,忘了基类!
    如果你不显式调用基类的拷贝构造,编译器会去调用基类的默认无参构造函数!导致你新对象的 m_age 变成了 0 或者随机值

❌ 错误姿势:忘了基类!导致 Person 部分被默认初始化,产生数据切片

cpp 复制代码
Student(const Student& other) { ... }

✅ 正确姿势:必须在初始化列表中显式调用 Person 的拷贝构造,传入 other!

💡 魔法点:这里把 Student 引用传给 Person 的引用参数,发生了我们之前讲过的"绝对安全"的向上转型!

cpp 复制代码
Student(const Student& other) : Person(other) {
        // 自己动手做深拷贝
        m_name = new char[strlen(other.m_name) + 1];
        strcpy(m_name, other.m_name);
        cout << "Student 拷贝构造" << endl;
    }

  1. 派生类的赋值运算符重载
  • 如何实现: 赋值重载同样需要处理两层逻辑
    • 一要防止自己赋值给自己
    • 二要显式调用基类的赋值重载,最后再处理自己的深拷贝
cpp 复制代码
// ✅ 正确姿势
    Student& operator=(const Student& other) {
        cout << "Student 赋值" << endl;
        // 1. 防身术:防止自己赋值给自己(极度危险,会导致自己的内存先被删掉)
        if (this == &other) {
            return *this;
        }

        // 2. 显式调用基类的赋值重载,处理基类部分的数据(age)
        // 💡 魔法点:显式指明作用域
        Person::operator=(other); 

        // 3. 处理派生类自己的深拷贝(先释放旧的,再分配新的)
        delete[] m_name; 
        m_name = new char[strlen(other.m_name) + 1];
        strcpy(m_name, other.m_name);

        return *this;
    }

  1. 派生类的析构函数
  • 如何实现: 在析构函数里,你只需要打扫派生类自己弄脏的屋子(释放 m_name)。绝对不要去显式调用 ~Person()

  • 底层机制: 编译器在执行完派生类的析构函数体后,会自动在底层插入对基类析构函数的调用。这就保证了先灭儿子,再灭老子的绝对顺序。如果你手贱调用了,会导致基类被析构两次

cpp 复制代码
// ✅ 正确姿势:只管好自己,剩下的交给编译器
    ~Student() { // 记得基类的析构函数一定要是 virtual 的!
        delete[] m_name;
        cout << "Student 析构" << endl;
        // 编译器会自动在这里偷偷加上:Person::~Person();
    }

6.3)图表解析

构造时先造老子后造儿子,析构时先灭儿子后灭老子


7. 实现一个不能被继承的类

方法 1:利用构造函数的私有性(C++98 时代的"黑科技")

派生类的构造函数必须调用基类的构造函数

如果你把基类的构造函数设为 private,那么派生类在实例化时,就会因为"看不见、调不动"父类的构造函数而导致编译报错

cpp 复制代码
class Base {
private:
    Base() {} // 1. 构造函数私有化:只有我自己能用,别人(包括儿子)都调不到
};

class Derived : public Base {
public:
    // ❌ 编译报错:'Base::Base()' is private
    // 因为 Derived 的构造函数必须先调用 Base 的构造函数,但 Base 把它藏起来了
    Derived() {} 
};

int main() {
    // Base b;    // ❌ 连基类自己也没法直接在外部实例化了
    // Derived d; // ❌ 派生类彻底废了
    return 0;
}

方法 2:使用 final 关键字(C++11 现代标准,最推荐)

C++11 引入了final关键字,直接从语法层面封死了继承的路
在类名后面直接加 final

cpp 复制代码
// 在类名后面直接加 final
class Base final {
public:
    Base() {}
};

// ❌ 编译报错:cannot derive from 'final' base 'Base' in derived type 'Derived'
class Derived : public Base {
};

8. 继承与友元

友元关系不能继承,也就是说基类友元不能访问派生类私有和保护成员

通俗地说:"你父亲的朋友(基类的友元),不一定是你的朋友(派生类的友元) 。"即便 Display 函数在 Person 里被声明为友元,它也只能看到 Student 对象中属于 Person 的那部分,而看不到 Student 自己特有的保护成员

cpp 复制代码
class Student;
class Person
{
public:
    friend void Display(const Person& p, const Student& s);

protected:
    string _name; // 姓名
};

class Student : public Person
{
protected:
    int _stuNum; // 学号
};

void Display(const Person& p, const Student& s)
{
    cout << p._name << endl;
    cout << s._stuNum << endl; // 编译报错:无法访问 protected 成员
}

int main()
{
    Person p;
    Student s;
    // 编译报错: error C2248: "Student::_stuNum": 无法访问 protected 成员
    // 解决方案: Display 也要成为 Student 的友元即可
    Display(p, s);

    return 0;
}
  1. DisplayPerson 的友元 → 它可以访问 Person_name

  2. Student 继承自 Person

  3. Display 试图访问 Student 特有的 _stuNum

  4. 结局:编译器拒绝

    因为 Display 并没有在 Student 类里获得"好友位"。


9. 继承与静态成员

基类定义了 static 静态成员,则整个继承体系里面只有一个 这样的成员。无论派生出多少个派生类,都只有一个 static 成员实例

cpp 复制代码
class Person
{
public:
    string _name;
    static int _count;
};

int Person::_count = 0;

class Student : public Person
{
protected:
    int _stuNum;

public:
    int main()
    {
        Person p;
        Student s;

        // 非静态成员 _name 的地址是不一样的
        // 说明派生类继承下来了,父类和派生类对象各有一份
        cout << &p._name << endl;
        cout << &s._name << endl;

        // 静态成员 _count 的地址是一样的
        // 说明派生类和基类共用同一份静态成员
        cout << &p._count << endl;
        cout << &s._count << endl;

        // 公有的情况下,通过父类或派生类类域都可以访问静态成员
        cout << Person::_count << endl;
        cout << Student::_count << endl;

        return 0;
    }
};

⭕10. 单继承、多继承 及其 菱形继承问题

10.1)单继承

一个派生类只从一个基类继承

cpp 复制代码
class Animal {
public:
    void eat() { cout << "正在进食..." << endl; }
};

class Dog : public Animal {
public:
    void bark() { cout << "汪汪汪!" << endl; }
};

内存模型

  • 布局: 内存中先排布 Animal 的成员,紧接着排布 Dog 的成员
  • 关系: 是一条直线:Animal -> Dog

10.2)多继承

多继承允许一个派生类同时从两个或多个基类继承

cpp 复制代码
//基类 A:沙发
class Sofa {
public:
    void sit() { cout << "坐着很舒服..." << endl; }
};

//基类 B:床
class Bed {
public:
    void sleep() { cout << "躺着很安稳..." << endl; }
};

//派生类:沙发床
class SofaBed : public Sofa, public Bed {
public:
    void fold() { cout << "正在折叠成沙发..." << endl; }
};

内存模型

  • 布局 :内存中会按照继承声明的顺序,先排布 Sofa 的成员,再排布 Bed 的成员,最后是 SofaBed 自己的成员。

  • 关系 :是一个多对一的结构: {Sofa, Bed} -> SofaBed


10.3)菱形继承问题

菱形继承 :菱形继承是多继承的一种特殊情况。菱形继承的问题,从下面的对象成员模型构造,可以看出菱形继承有数据冗余二义性 的问题,在 Assistant 的对象中 Person 成员会有两份


10.4)虚继承

C++语法复杂,多继承就是一个体现。

有了多继承,就存在菱形继承;

有了菱形继承就会有菱形虚拟继承

我们观察下面的代码

cpp 复制代码
class Person
{
public:
    string _name; // 姓名
    /*int _tel;
    int _age;
    string _gender;
    string _address;*/
};

//使用虚继承 Person 类
class Student : virtual public Person
{
protected:
    int _num; // 学号
};

//使用虚继承 Person 类
class Teacher : virtual public Person
{
protected:
    int _id; // 职工编号
};

//教授助理
class Assistant : public Student, public Teacher
{
protected:
    string _majorCourse; // 主修课程
};

int main()
{
    //使用虚继承,可以解决数据冗余和二义性
    Assistant a;
    a._name = "peter";
    return 0;
}

virtual 必须加在产生"分叉"的地方,而不是"汇合"的地方


10.5)多继承中的指针偏移问题

cpp 复制代码
class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };

int main()
{
    Derive d;
    Base1* p1 = &d;
    Base2* p2 = &d;
    Derive* p3 = &d;

    return 0;
}
指针变量 指向类型 实际地址值 说明
p3 Derive* 0x100 指向对象开头
p1 Base1* 0x100 因为 Base1 在开头,所以和 p3 相等
p2 Base2* 0x104 发生了偏移!跳过了 Base1 的空间

11. 继承与组合

继承是 is-a 关系
组合是 has-a 关系

cpp 复制代码
class Engine {
public:
    void start() { /* 引擎启动逻辑 */ }
};

class Car {
private:
    Engine _eng; // 组合:引擎是 Car 的一个成员
public:
    void run() {
        _eng.start(); // ✅ 黑箱复用:Car 只管用 Engine 的公开接口,不关心其内部怎么喷油的
        cout << "汽车行驶中..." << endl;
    }
};

Engine 内部怎么改,只要 start() 接口不变,Car 就不受影响。每个类都保持了良好的封装性


为什么优先使用组合(Has-A)?

  • 组合 :宿主类只知道成员类的 public 接口。成员类内部怎么改(甚至改了成员变量名),只要接口不变,宿主类代码一行都不用动。

  • 继承 :派生类可以看到基类的 protected 成员。基类一旦改动内部逻辑,往往会引发派生类的连锁崩溃。这被称为**"脆弱的基类问题"**


什么时候必须用继承

C++ 的灵魂------多态,必须依赖继承

场景需求 推荐方案 理由
我想借用另一个类的功能代码 组合 借用工具而已,没必要认爹,保持代码独立性。
我想在运行时更换某个组件 组合 插件式设计,极其灵活。
我需要实现接口的一致性(多态) 继承 只有继承能让你在父类指针下操作不同子类。
两个类有严格的层级和分类关系 继承 符合人类直觉,逻辑清晰。
我想隐藏基类的复杂实现细节 组合 继承会暴露太多 protected 内容给子类。

💻结尾--- 核心连接协议

警告: 🌠🌠正在接入底层技术矩阵。如果你已成功破解学习中的逻辑断层,请执行以下指令序列以同步数据:🌠🌠


【📡】 建立深度链接: 关注本终端。在赛博丛林中深耕底层架构,从原始代码到进阶协议,同步见证每一次系统升级。

【⚡】 能量过载分发: 执行点赞操作。通过高带宽分发,让优质模组在信息流中高亮显示,赋予知识跨维度的传播力。

【💾】 离线缓存核心: 将本页加入收藏。把这些高频实战逻辑存入你的离线存储器,在遭遇系统崩溃或需要离线检索时,实现瞬时读取。

【💬】 协议加密解密:评论区留下你的散列码。分享你曾遭遇的代码冲突或系统漏洞(那些年踩过的坑),通过交互式编译共同绕过技术陷阱。

【🛰️】 信号频率投票: 通过投票发射你的选择。你的每一次点击都在重新定义矩阵的进化方向,决定下一个被全量拆解的技术节点。



相关推荐
苏宸啊3 小时前
IPC管道
linux·c++
BestOrNothing_20154 小时前
ROS2 话题通信实战:消息对象、Publisher 发布器与 Subscriber 订阅器保姆级教程
c++·ros2·subscriber·publisher·话题通信
艾iYYY5 小时前
string 类的模拟实现
android·服务器·c语言·c++·算法
为何创造硅基生物5 小时前
C++ virtual void StartNetwork() = 0; // 纯虚:子类必须实现,否则不能 new。
c++
知无不研6 小时前
对套接字的深入理解
linux·服务器·网络·c++·socket·网络套接字
hai3152475437 小时前
FlashAttention C语言(C++)实现(展示版)
c语言·开发语言·c++·人工智能·算法
wuminyu8 小时前
Java锁机制之Java对象重量级锁源码剖析
java·linux·c语言·jvm·c++
郝学胜_神的一滴9 小时前
Qt 高级开发 026:QTabWidget御道,从筑基到化境
c++·qt
apocelipes9 小时前
GNU GCC 多版本函数扩展
c语言·c++·linux编程
代码中介商9 小时前
C++完美转发与引用折叠全解析
开发语言·c++