面试题答案
一键面试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()
。同样,使用指针传递也能达到保持多态性的效果。