1.10 C++ 面向对象(重头戏)

一、面向对象和面向过程区别

面向过程:强调过程的抽象化和模块化以过程为中心处理客观世界问题

面向对象:强调把解决问题的方法直接绑定到对象身上

二、 面向对象的基本特征有哪些?

抽象(抽象出共同的、本质的特征)、继承(基类与派生类)、封装(将数据和方法封装在一个类中,只提供一些公有接口来访问)、多态(相同方法在不同对象上的表现不同)。

三、什么是深拷贝和浅拷贝

主要是针对指针成员变量来说的,深拷贝要求重新申请一段新的内存,将源对象指针所指向的内存内容拷贝到新对象中。浅拷贝就会简单的进行指针赋值。

四、什么是友元

一些类会给成员以外的函数或类(即友元函数、友元类)提供访问、操作自身成员变量(包括私有变量和保护变量)的机会,但是这种赋权是单向的(友元类、友元方法可以操作该类的私有成员,但反过来不行)

#include <iostream>
using namespace std;

class BankAccount {
private:
    double balance;  // 私有成员,外部无法直接访问

public:
    BankAccount(double b) : balance(b) {}

    // 声明审计函数为友元(允许访问私有成员)
    friend void audit(const BankAccount& account);
};

// 友元函数定义(可以访问BankAccount的私有成员)
void audit(const BankAccount& account) {
    cout << "[审计] 当前余额: " << account.balance << endl;  // 直接访问私有成员
}

int main() {
    BankAccount acc(1000.0);
    audit(acc);  // 输出: [审计] 当前余额: 1000
    return 0;
}

特性

友元函数

友元类

访问权限

可以访问目标类的私有(private)和保护(protected)成员

该类的所有成员函数均可访问目标类的私有和保护成员

定义方式

在类内使用 friend [返回值] 函数名(参数);声明

在类内使用 friend class 类名;声明

访问方式

需通过对象实例或指针/引用访问成员(如 obj.private_var

可直接访问目标类成员(无需通过实例)

关系方向

单向:目标类成员函数不能访问友元函数的局部变量

单向:目标类成员函数不能访问友元类的私有成员(除非友元类反向声明)

典型应用场景

1. 运算符重载(<</>>)2. 工具函数3. 单元测试辅助函数

1. 紧密协作的类(如容器-迭代器)2. 工厂模式3. 复杂系统内部模块

五、基类的构造函数、析构函数能否被派生类继承?

不能。首先二者名字就不一样,其次基类与派生类的资源管理需求也不一样,构造函数、析构函数有其自身的调用机制。

六、初始化列表和构造函数初始化的区别?

初始化列表会先于构造函数执行,也就是在定义阶段执行const或引用类型成员初始化时,只能用初始化列表的方式;以及派生类对基类传递值进行初始化的时候;以及没有默认构造函数的成员类(因为如果不进行显示初始化,编译器将自动调用其默认构造函数,但是没有默认构造函数,然后就会报错)。

七、类的成员变量的初始化顺序

按在类中声明的顺序依次初始化,与初始化列表的顺序无关。

若使用构造函数初始化,则与构造函数中的初始化顺序有关。

在 c++11 以前,普通变量成员不能进行类内初始化;c++11 之后可以,类内初始化会被编译器合并到构造函数的初始化列表中,若同时存在类内初始化和构造函数初始化列表,后者会覆盖前者

在 c++17 以前,静态成员必须在类外单独初始化;c++17 引入 内联静态成员,允许在类内初始化:

class MyClass {
    static int count;       // 声明
    static constexpr float PI = 3.14f;  // 声明+初始化
};
int MyClass::count = 0;    // 必须类外定义
class MyClass {
    static inline int count = 0;  // 声明+定义+初始化
    static constexpr float PI = 3.14f;  // 同C++11
};
// 无需类外定义!

底层原理

  • inline告诉编译器:
  • 该变量的定义可以出现在多个翻译单元(.cpp文件)中。
  • 链接器会合并所有重复定义,最终只保留一个实例,在程序全局数据区有唯一地址。

八、public 继承、protected 继承、private 继承的区别?

公有继承会向下传递,公有部分在其子孙派生类中将一直是公有部分。

保护继承会使得只能通过其最近派生类访问被继承的类。基类的公有部分和保护部分全都将变为派生类的保护部分。

私有继承使基类的一切都将变为私有,在第三代的时候会导致完全屏蔽,第三代只能通过第二代的公有接口访问基类的公有接口,进而访问基类的私有成员。

九、虚继承

解决棱形继承的问题。避免对爷爷成员变量访问的二义性。会由编译器选择一个中间类的虚基类指针找到基类的数据。

内存布局:

普通继承

D的内存布局:[B::A::data] [C::A::data] [D的成员](两份 data)。

虚继承

D的内存布局:[虚基类指针] [B的成员] [C的成员] [A::data] [D的成员](只有一份 data)。

十、C++ 类内可以定义引用数据成员吗?

可以,必须通过成员函数初始化列表初始化。

十一、泛型编程是什么?

让类型参数化,是程序可以从逻辑功能上抽象,把被处理对象的类型作为参数传递。c++ 里面主要通过模板实现(函数模板、类模板)。类模板可以进行 类型参数化值参数化

template <typename T, int size>  // 使用值参数 size

class Array {
private:
    T arr[size];
public:
    T& operator[](int index) {
        return arr[index];
    }
}

模板特化(模板函数、模板类):

template <typename T>
void print(T value) {
    cout << "Generic: " << value << endl;
}

//针对 int类型的特化
template
void print<int>(int value) {
    cout << "Specialized for int: "<< value << en

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

C++/嵌入式开发 秋招面经 文章被收录于专栏

一名985硕,在25年秋招中斩获多个C++/嵌入式开发Offer。本专栏将分享我的面经,涵盖C/C++、操作系统、计算机网络、ARM体系与架构、Linux应用/驱动开发、Qt、通信协议及开发工具链等核心内容。

全部评论
求问深拷贝场景
1 回复 分享
发布于 04-02 20:51 河北
蹲个面经
点赞 回复 分享
发布于 昨天 00:18 河北
欢迎订阅专栏《C++/嵌入式开发 秋招面经》 :https://www.nowcoder.com/creation/manager/columnDetail/MKaoll
点赞 回复 分享
发布于 03-30 17:05 河北

相关推荐

评论
5
3
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务