MST

星途 面试题库

面试题:C++ 多态必要条件验证之专家难度

在C++11引入移动语义和右值引用的背景下,结合多态的必要条件,探讨如何优化含有虚函数的类在移动操作中的性能。请详细阐述原理并给出代码示例进行验证。
32.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

原理阐述

  1. 移动语义和右值引用基础
    • C++11 引入右值引用 &&,用于标识临时对象(右值)。移动语义利用右值引用,使得资源所有权可以高效地从一个对象转移到另一个对象,而不是进行深度拷贝。例如,对于一个包含动态分配内存的对象,移动操作只需转移指针和重置源对象,而拷贝操作需要分配新内存并复制数据。
    • 移动构造函数和移动赋值运算符的声明形式如下:
      class MyClass {
      public:
        MyClass(MyClass&& other) noexcept; // 移动构造函数
        MyClass& operator=(MyClass&& other) noexcept; // 移动赋值运算符
      };
      
  2. 多态与虚函数
    • 多态的必要条件是:基类中定义虚函数,派生类重写这些虚函数,通过基类指针或引用调用虚函数。
    • 当一个类含有虚函数时,它会有一个虚函数表指针(vptr),用于在运行时确定实际调用的函数。这增加了对象的大小和一定的开销。
  3. 优化含有虚函数类的移动操作性能
    • 在移动含有虚函数的类对象时,关键是要高效地转移资源而不影响虚函数机制。由于虚函数表指针是对象的一部分,移动时直接转移 vptr 即可,它指向的虚函数表在整个程序中是共享的,不需要额外操作。对于其他资源(如动态分配的内存),按照常规移动语义处理,即转移指针并重置源对象。

代码示例

#include <iostream>
#include <memory>

class Base {
public:
    virtual ~Base() = default;
    virtual void print() const {
        std::cout << "Base" << std::endl;
    }
};

class Derived : public Base {
private:
    std::unique_ptr<int[]> data;
    int size;
public:
    Derived(int s) : size(s), data(std::make_unique<int[]>(s)) {
        for (int i = 0; i < s; ++i) {
            data[i] = i;
        }
    }

    // 移动构造函数
    Derived(Derived&& other) noexcept : size(other.size), data(std::move(other.data)) {
        other.size = 0;
        other.data = nullptr;
    }

    // 移动赋值运算符
    Derived& operator=(Derived&& other) noexcept {
        if (this != &other) {
            size = other.size;
            data = std::move(other.data);
            other.size = 0;
            other.data = nullptr;
        }
        return *this;
    }

    void print() const override {
        std::cout << "Derived" << std::endl;
    }
};

void test_move(Base&& base) {
    Base* ptr = &base;
    ptr->print();
}

int main() {
    Derived d1(5);
    test_move(std::move(d1));
    return 0;
}

在上述代码中:

  • Base 类是一个含有虚函数的基类。
  • Derived 类继承自 Base 并含有动态分配的内存(通过 std::unique_ptr<int[]>)。
  • Derived 类提供了移动构造函数和移动赋值运算符,高效地转移 data 指针,同时不影响虚函数机制。
  • test_move 函数接受一个右值引用的 Base 对象,通过基类指针调用虚函数 print,展示了移动语义在多态场景下的正常工作。