但值得注意的是Vehicle(speed,total)的意义并不是对Vehicle类的个个成员的初始化,事实上是利用它创建了一个Vehicle类的无名对象,由于Car类对象的覆盖范围是覆盖于Vehicle类和Car类上,所以系统在确定了派生类对象a的空间范围后,确定了this指针位置,这个this指针指向了Vehicle类的那个无名对象,这个成员赋值过程就是,this->speed=无名对象.speed。
其实这里概念比较模糊,笔者因为个人能力的原因暂时也无法说的更明确了,读者对此处知识点的学习,应该靠自己多对比多练习,进行体会理解。
许多书籍对于派生类对象的复制这一知识点多是空缺的,为了教程的易读性,我还是决定说一下在复制过程中容易出错的地方,Car b=a;是派生类对象复制的语句,通过前面教程的学习我们我们知道,类对象的复制是通过拷贝构造函数来完成的,如果上面的例子我们没有提供拷贝构造函数不完整如下: Car(Car &temp) { cout<<"载入Car类拷贝构造函数"<<endl; Car::aird = temp.aird; } 那么复制过程中就会丢失基类成员的数据了,所以Car类拷贝构造函数不能缺少Vehicle类无名对象的创建过程:Vehicle(temp.speed,temp.total),派生类对象的复制过程系统是不会再调用基类的拷贝构造函数的,this指针的问题再次在这里体现出来,大家可以尝试着把无名对象的创建去掉,观察b.speed的变化。
类对象够创建必然就有析构过程,派生类对象的析构过程首先是调用派生类的析构过程,再调用基类的构造函数,正好和创建过程相反,在这里笔者已经在上面代码中加入了过程显示,读者可以自行编译后观察。 最后我们说一下类的继承与组合。
其实类的组合我们在早些的前面的教程就已经接触过,只是在这里换了个说法而已,当一个类的成员是另一个类的对象的时候就叫做组合,事实上就是类于类的组合。组合和继承是有明显分别的,为了充分理解继承与组合的关系,我们在不破坏类的封装特性的情况下,先看如下的代码: #include <iostream> using namespace std; class Vehicle { public: Vehicle(float speed=0,int total=0) { Vehicle::speed = speed; Vehicle::total = total; } protected: float speed;//速度 int total;//最大载人量 }; class Motor { public: Motor(char *motor) { Motor::motortype = motor; } char* SMT(Motor &temp); protected: char *motortype;//发动机型号 }; char* Motor::SMT(Motor &temp) { return temp.motortype; } class Car:public Vehicle//继承的体现 { public: Car(float speed,int total,int aird,char *motortype):Vehicle(speed,total),motor(motortype) { Car::aird = aird; } Motor rm(Car &temp); protected: int aird;//排量 Motor motor;//类组合的体现 }; Motor Car::rm(Car &temp) { return temp.motor; } //-------------------------------------------------------------- void test1(Vehicle &temp) { //中间过程省略 }; void test2(Motor &temp) { cout<<temp.SMT(temp);//读者这里注意一下,temp既是对象也是对象方法的形参 } //-------------------------------------------------------------- void main() { Car a(150,4,250,"奥地利AVL V8"); test1(a); //test2(a);//错误,Car类与Motor类无任何继承关系 test2(a.rm(a));//如果Car类成员是public的那么可以使用test2(a.motor) cin.get(); } 在上面的代码中我们新增加了发动机类Motor,Car类增加了Motor类型的motor成员,这就是组合,拥有继承特性的派生类可以操作基类的任何成员,但对于与派生类组合起来的普通类对象来说,它是不会和基类有任何联系的。
函数调用:test1(a);,可以成功执行的原因就是因为Car类对象在系统是看来一个Vehicle类对象,即Car类是Vehicle类的一种,Car类的覆盖范围包含了Vehicle。 函数调用:test2(a);,执行错误的原因是因为Motor类并不认可Car类对象a与它有任何关系,但我们可以通过使用Car类对象a的Motor类成员motor,作为函数形参的方式来调用test2函数(test2(a.motor)),在这里由于类的成员是受保护的所以我们利用a.rm(a)来返回受保护的motor,作为函数参数进行调用。
|