类与对象(下)

前言:

在 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;
}
相关推荐
Moment1 天前
前端工程化 + AI 赋能,从需求到运维一条龙怎么搭 ❓❓❓
前端·javascript·面试
没有bug.的程序员1 天前
Serverless 弹性扩容引发的全线熔断:Spring Boot 启动耗时从 1s 压缩至 0.3s 的物理级绞杀
java·spring boot·kubernetes·serverless·扩容·线上
bearpping1 天前
java进阶知识点
java·开发语言
Joker Zxc1 天前
【前端基础(Javascript部分)】6、用JavaScript的递归函数和for循环,计算斐波那契数列的第 n 项值
开发语言·前端·javascript
独自破碎E1 天前
【面试真题拆解】你知道ThreadLocal是什么吗
java·jvm·面试
kkkkatoq1 天前
JAVA中的IO操作
java·开发语言
Highcharts.js1 天前
React 图表如何实现下钻(Drilldown)效果
开发语言·前端·javascript·react.js·前端框架·数据可视化·highcharts
chushiyunen1 天前
python中的魔术方法(双下划线)
前端·javascript·python
深蓝轨迹1 天前
@Autowired与@Resource:Spring依赖注入注解核心差异剖析
java·python·spring·注解
不想看见4041 天前
C++八股文【详细总结】
java·开发语言·c++