简单继承的例子:
1 #include <iostream> 2 #include <string> 3 using namespace std; 4 5 class CStudent 6 { 7 private: 8 string name; 9 string id; //学号 10 char gender; //性别,‘F‘代表女, ‘M‘代表男 11 int age; 12 public: 13 void PrintInfo(); 14 void SetInfo( const string & name_,const string & id_, 15 int age_, char gender_ ); 16 string GetName() { return name; } 17 }; 18 19 void CStudent::PrintInfo() 20 { 21 cout << "Name:" << name << endl; 22 cout << "ID:" << id << endl; 23 cout << "Age:" << age << endl; 24 cout << "Gender:" << gender << endl; 25 } 26 27 void CStudent::SetInfo( const string & name_,const string & id_, 28 int age_,char gender_ ) 29 { 30 name = name_; 31 id = id_; 32 age = age_; 33 gender = gender_; 34 } 35 36 class CUndergraduateStudent : public CStudent 37 { 38 //本科生类,继承了CStudent类 39 private: 40 string department; //学生所属的系的名称 41 public: 42 void QualifiedForBaoyan() 43 { 44 //给予保研资格 45 cout << “qualified for baoyan” << endl; 46 } 47 48 void PrintInfo() 49 { 50 CStudent::PrintInfo(); //调用基类的PrintInfo 51 cout << “Department:” << department <<endl; 52 } 53 54 void SetInfo( const string & name_,const string & id_, 55 int age_,char gender_ ,const string & department_) 56 { 57 CStudent::SetInfo(name_,id_,age_,gender_); //调用基类的SetInfo 58 department = department_; 59 } 60 }; 61 62 int main() 63 { 64 CUndergraduateStudent s2; 65 s2.SetInfo(“Harry Potter ”, “118829212”,19,‘M’,“Computer Science”); 66 cout << s2.GetName() << “ ” ; 67 s2.QualifiedForBaoyan (); 68 s2.PrintInfo (); 69 return 0; 70 }
类之间的两种关系
(1)继承:“是”关系。
基类 A, B是基类A的派生类。逻辑上要求:“一个B对象也是一个A对象”。
(2)复合:“有”关系。
类C中“有” 成员变量k, k是类D的对象,则C和D是复合关系,一般逻辑上要求:“ D对象是C对象的固有属性或组成部分”。
几何形体程序中,需要写“点”类,也需要写“圆”类
1 class CPoint 2 { 3 double x,y; 4 }; 5 6 class CCircle : public CPoint 7 { 8 double r; 9 };
这是不合理的,应该使用复合关系;每一个“圆”对象里都包含(有)一个“点”对象,这个“点”对象就是圆心
1 class CPoint 2 { 3 double x,y; 4 //便于Ccirle类操作其圆心 5 friend class CCircle; 6 }; 7 8 class CCircle 9 { 10 double r; 11 CPoint center; 12 };
覆盖
派生类可以定义一个和基类成员同名的成员,这叫覆盖。在派生类中访问这类成员时,缺省的情况是访问派生类中定义的成员。要在派生类中访问由基类定义的同名成员时,要使用作用域符号“::”
访问控制符
以下均表示可以被下列函数访问
1、基类的private成员:
(1)基类的成员函数
(2)基类的友员函数
2、基类的public成员:
(1)基类的成员函数
(2)基类的友员函数
(3)派生类的成员函数
(4)派生类的友员函数
(5)其他的函数
3、基类的protected成员:
(1)基类的成员函数
(2)基类的友员函数
(3)派生类的成员函数可以访问当前对象的基类的保护成员
1 class Father 2 { 3 private: 4 int nPrivate; //私有成员 5 public: 6 int nPublic; //公有成员 7 protected: 8 int nProtected; // 保护成员 9 }; 10 11 class Son : public Father 12 { 13 void AccessFather () 14 { 15 nPublic = 1; // ok; 16 nPrivate = 1; // wrong 17 nProtected = 1; // OK,访问从基类继承的protected成员 18 Son f; 19 f.nProtected = 1; //wrong ,f不是当前对象 20 } 21 }; 22 23 int main() 24 { 25 Father f; 26 Son s; 27 f.nPublic = 1; // Ok 28 s.nPublic = 1; // Ok 29 f.nProtected = 1; // error 30 f.nPrivate = 1; // error 31 s.nProtected = 1; //error 32 s.nPrivate = 1; // error 33 return 0; 34 }
派生类的构造函数
在创建派生类的对象时,需要调用基类的构造函数:初始化派生类对象中从基类继承的成员。在执行一个派生类的构造函数之前,总是先执行基类的构造函数。
调用基类构造函数的两种方式
(1)显式方式:在派生类的构造函数中,为基类的构造函数提供参数.derived::derived(arg_derived-list):base(arg_base-list)
(2)隐式方式:在派生类的构造函数中,省略基类构造函数时,派生类的构造函数则自动调用基类的默认构造函数.
派生类的析构函数被执行时,执行完派生类的析构函数后,自动调用基类的析构函数。
在创建派生类的对象时:
(1)先执行基类的构造函数,用以初始化派生类对象中从基类继承的成员;
(2)再执行成员对象类的构造函数,用以初始化派生类对象中成员对象。
(3)最后执行派生类自己的构造函数
在派生类对象消亡时:
(1)先执行派生类自己的析构函数
(2)再依次执行各成员对象类的析构函数
(3)最后执行基类的析构函数
析构函数的调用顺序与构造函数的调用顺序相反。
赋值规则
(1)派生类的对象可以赋值给基类对象
b = d;
(2)派生类对象可以初始化基类引用
base & br = d;
(3)派生类对象的地址可以赋值给基类指针
base * pb = & d;
如果派生方式是 private或protected,则上述三条不可行。
公有派生的情况下,派生类对象的指针可以直接赋值给基类指针
Base * ptrBase = &objDerived;
(1)ptrBase指向的是一个Derived类的对象;
*ptrBase可以看作一个Base类的对象,访问它的public成员直接通过ptrBase即可,但不能通过ptrBase访问objDerived对象中属于Derived类而不属于Base类的成员
(2)即便基类指针指向的是一个派生类的对象,也不能通过基类指针访问基类没有,而派生类中有的成员。
(3)通过强制指针类型转换,可以把ptrBase转换成Derived类的指针
Base * ptrBase = &objDerived;
Derived *ptrDerived = (Derived * ) ptrBase;
要保证ptrBase指向的是一个Derived类的对象,否则很容易会出错。