MST
星途 面试题库

面试题:C++非虚函数声明在复杂场景下的深度分析

在一个多线程环境下,有一个基类`ResourceManager`,其中有一个非虚函数`getResource`用于获取资源。多个派生类如`DatabaseResourceManager`、`FileResourceManager`继承自`ResourceManager`。考虑到多线程安全以及非虚函数声明的规则,分析`getResource`函数在不同派生类中的实现需要注意哪些方面?编写示例代码展示如何确保线程安全且符合非虚函数声明规则,同时阐述这样实现背后的原理。
38.6万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 分析getResource函数在不同派生类中的实现需要注意的方面

  • 多线程安全:由于是多线程环境,需要确保对共享资源(如资源获取过程中的中间数据、资源本身等)的访问是线程安全的。这可能涉及到使用锁(如互斥锁std::mutex)来保护临界区,防止多个线程同时访问导致数据竞争。
  • 非虚函数声明规则:非虚函数在基类中声明后,派生类不能改变其接口(函数签名)。派生类实现该函数时,应确保其功能符合基类对该函数的预期语义,并且在多线程环境下的实现不会破坏基类中关于该函数的整体设计意图。

2. 示例代码

#include <iostream>
#include <mutex>
#include <thread>

class ResourceManager {
public:
    // 非虚函数
    void getResource() {
        std::cout << "Base ResourceManager getting resource." << std::endl;
    }
};

class DatabaseResourceManager : public ResourceManager {
private:
    std::mutex mtx;
public:
    void getResource() override {
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "DatabaseResourceManager getting database resource." << std::endl;
    }
};

class FileResourceManager : public ResourceManager {
private:
    std::mutex mtx;
public:
    void getResource() override {
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "FileResourceManager getting file resource." << std::endl;
    }
};

void threadFunction(ResourceManager& rm) {
    rm.getResource();
}

int main() {
    DatabaseResourceManager dbRm;
    FileResourceManager fileRm;

    std::thread t1(threadFunction, std::ref(dbRm));
    std::thread t2(threadFunction, std::ref(fileRm));

    t1.join();
    t2.join();

    return 0;
}

3. 原理阐述

  • 多线程安全原理:在派生类DatabaseResourceManagerFileResourceManager中,使用std::mutexstd::lock_guard来保护getResource函数的执行。std::lock_guard在构造时自动锁定互斥锁,在析构时自动解锁,从而确保在getResource函数执行期间,不会有其他线程同时进入该函数,避免了数据竞争。
  • 非虚函数声明规则原理:在C++中,虽然派生类不能改变非虚函数的接口,但可以通过override关键字显式表明该函数是对基类非虚函数的重定义(虽然这种重定义不同于虚函数的覆盖)。这有助于提高代码的可读性和可维护性,同时确保派生类的实现符合基类的接口要求。在多线程环境下,这种接口一致性也有助于确保各个派生类在多线程操作中的行为可预测性。