MST

星途 面试题库

面试题:C++按值传递在复杂类层次结构中的行为剖析

假设有一个复杂的类层次结构,基类包含虚函数,派生类对虚函数进行重写。当使用按值传递将派生类对象传递给一个接受基类对象作为参数的函数时,分析在传递过程中发生了什么,包括切片问题是如何产生的,以及对多态性的影响,请通过详细代码示例说明。
28.3万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

1. 切片问题分析

当使用按值传递将派生类对象传递给接受基类对象作为参数的函数时,会发生切片(slicing)现象。这是因为按值传递会创建对象的副本,而在传递派生类对象给接受基类对象的函数时,只会复制基类部分的数据成员,派生类特有的数据成员会被 “切掉”,从而丢失了派生类的额外信息。

2. 对多态性的影响

多态性依赖于对象的动态类型。由于切片,传递给函数的对象的动态类型被改变为基类类型,导致在函数内部调用虚函数时,不会调用派生类重写的版本,而是调用基类的版本,破坏了多态性。

3. 代码示例

#include <iostream>

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

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

void process(Base b) {
    b.print();
}

int main() {
    Derived d;
    process(d);
    return 0;
}

在上述代码中:

  • Base 类有一个虚函数 print
  • Derived 类继承自 Base 类并重写了 print 函数。
  • process 函数接受一个 Base 类型的对象参数。
  • main 函数中,创建了一个 Derived 对象 d 并传递给 process 函数。由于按值传递发生切片,process 函数内部调用的 print 函数是 Base 类的版本,而不是 Derived 类重写的版本,输出为 Base::print()。如果想要保持多态性,参数应该使用指针或引用传递,如下:
#include <iostream>

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

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

void process(const Base& b) {
    b.print();
}

int main() {
    Derived d;
    process(d);
    return 0;
}

在修改后的代码中,process 函数接受 Base 类型的引用参数,这样不会发生切片,process 函数内部调用 print 函数时会根据对象的实际类型(即 Derived 类型)调用 Derived 类重写的 print 函数,输出为 Derived::print()。同样,使用指针传递也能达到保持多态性的效果。