今天看代码时,遇到一个问题:
#include <iostream> using namespace std; class Point{ public: Point(double i,double j){x=i;y=j;} virtual double area()const; private: double x,y; }; double Point::area()const{ return 0; } class Rectangle:public Point{ public: Rectangle(int i,int j,int k,int l); double area()const; private: double w,h; }; Rectangle::Rectangle(int i,int j,int k,int l):Point(i,j){ w=k; h=l; } double Rectangle::area() const{ return w*h; } //void fun(Point &s) 结果将如何? void fun(Point s){ cout<< "Fun: " << s.area()<<endl; } int main(){ Rectangle rect(3.0,5.2,15.0,25.0); cout<< "Main: " << rect.area() <<endl; fun(rect); return 0; }
这里传引用和传值有什么区别呢?
其实传值时就相当于,使用类型对象B(实参)去给类型对象A(形参)初始化。是不是有点熟悉了?
没错就是拷贝构造函数做的事情。虽然AB类型不一致。但是创建B对象的类类型是创建A对象的类类型的派生类。
这种情况下并不会产生类型不匹配的错误。
相反的会调用类类型A的拷贝构造函数对A初始化。那实参多出来的部分呢? 被消减了!
这就是多态中传值的一个问题——slicing(对象切割)问题。
当一个 derived class(派生类)对象以 值传递方式并被视为一个 基类的对象时,基类的拷贝构造函数会被调用,从而“造成此对象的行为像个 派生对象”的那些特化性质全被切割掉了,仅仅留下一个 基类对象(因为正是 基类的构造函数建立了它)。
正是因为上面的原因,所以 值传递方式不会实现多态的。实现多态的方法就是 通过传递 指针或者引用,因为这样传递的是 指向派生类的基类指针,派生类的特性会全部保留,不会因为切割而丢失。