类与对象(下)

前言:

在 C++ 面向对象编程中,类与对象是代码组织的核心,但想要真正驾驭它,需要深入理解那些"藏在背后"的进阶特性。从再探构造函数的细节,到对象拷贝时的编译优化,每一个知识点都能让你写出更高效、更优雅的代码。

一、再探构造函数:不止是"初始化"

构造函数是创建对象时自动调用的特殊函数,但它的作用远不止给成员变量赋值:

  • 默认构造函数:如果没有显式定义任何构造函数,编译器会自动生成一个空的默认构造函数;但如果定义了带参数的构造函数,默认构造函数会"消失",需要手动声明。

  • 拷贝构造函数:用一个已存在的对象初始化新对象时调用,默认的拷贝构造函数会做"浅拷贝"------只复制成员变量的值,对于指针等资源会导致"双重释放"问题,需要手动实现"深拷贝"。

  • 移动构造函数(C++11+):当对象是"临时值"(如函数返回的局部对象)时,移动构造函数会"接管"原对象的资源,避免不必要的拷贝,大幅提升效率。

二、类型转换:让对象"灵活变身"

C++ 允许类之间的隐式或显式类型转换,主要通过两种方式实现:

  • 构造函数转换:如果一个构造函数只接受一个参数(或除第一个参数外其他参数都有默认值),它可以将该类型的值隐式转换为类对象。

  • 类型转换函数:在类中定义一个无参数、无返回值声明(但需要返回目标类型)的函数,格式为 operator 目标类型() ,用于将类对象转换为其他类型。

示例:类型转换函数

复制代码
class MyInt {
private:
    int value;
public:
    MyInt(int v) : value(v) {}
    // 转换为 int 类型
    operator int() const {
        return value;
    }
};

int main() {
    MyInt a(10);
    int b = a; // 自动调用 operator int()
    cout << b << endl; // 输出 10
    return 0;
}

三、static 成员:属于类的"共享资源"

static 关键字可以修饰类的成员变量和成员函数:

  • static 成员变量:不属于任何对象,而是属于整个类,所有对象共享同一份值;需要在类外单独初始化,格式为 类型 类名::成员变量名 = 初始值 。

  • static 成员函数:没有 this 指针,只能访问 static 成员变量和其他 static 成员函数,不能访问非 static 成员;可以通过类名直接调用,无需创建对象。

    class Counter {
    private:
    static int count; // 声明 static 成员变量
    public:
    Counter() { count++; }
    static int getCount() { // static 成员函数
    return count;
    }
    };

    int Counter::count = 0; // 初始化 static 成员变量

    int main() {
    Counter a, b, c;
    cout << Counter::getCount() << endl; // 输出 3
    return 0;
    }

四、友元:打破封装的"特殊通道"

五、内部类:类里的"小类"

在一个类的内部定义另一个类,称为内部类(也叫嵌套类):

  • 内部类是一个独立的类,不属于外部类的成员,只是作用域被限制在外部类中;

  • 内部类可以直接访问外部类的 static 成员,但不能直接访问外部类的非 static 成员,需要通过外部类的对象来访问;

  • 外部类不能直接访问内部类的成员,需要创建内部类的对象。

示例:内部类的定义

复制代码
class Outer {
private:
    int outerValue = 10;
public:
    class Inner { // 内部类
    public:
        void showOuter(Outer& o) {
            cout << o.outerValue << endl; // 访问外部类的非 static 成员
        }
    };
};

int main() {
    Outer o;
    Outer::Inner i;
    i.showOuter(o); // 输出 10
    return 0;
}

六、匿名对象:"即用即弃"的临时对象

匿名对象是没有名字的对象,通常用于临时调用成员函数或作为函数参数:

  • 匿名对象的生命周期只在当前行,执行完当前行后会被销毁;

  • 可以简化代码,避免创建不必要的命名对象。

示例:匿名对象的使用

复制代码
class Printer {
public:
    void print(const char* str) {
        cout << str << endl;
    }
};

int main() {
    Printer().print("Hello, Anonymous!"); // 匿名对象调用成员函数
    return 0;
}
相关推荐
code_li44 分钟前
聊聊支付宝架构
java·开发语言·架构
yuguo.im1 小时前
我开源了一个 GrapesJS 插件
前端·javascript·开源·grapesjs
安且惜1 小时前
带弹窗的页面--以表格形式展示
前端·javascript·vue.js
被星1砸昏头1 小时前
掌握Python魔法方法(Magic Methods)
jvm·数据库·python
CC.GG1 小时前
【Linux】进程概念(五)(虚拟地址空间----建立宏观认知)
java·linux·运维
摘星编程2 小时前
用React Native开发OpenHarmony应用:NFC读取标签数据
javascript·react native·react.js
以太浮标2 小时前
华为eNSP模拟器综合实验之- AC+AP无线网络调优与高密场景
java·服务器·华为
Mr__Miss2 小时前
JAVA面试-框架篇
java·spring·面试
偷星星的贼112 小时前
数据分析与科学计算
jvm·数据库·python
小马爱打代码2 小时前
SpringBoot:封装 starter
java·spring boot·后端