C++类的继承的基本认识
一.继承的含义
继承是面向对象复用的重要手段。通过继承定义一个类,它们的类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。
二.继承关系与访问限定符
有如下总结:
1.基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保护成员。可以看出保护成员限定符是因继承才出现的。
例如:
classDate{public:Date(){cout<<"Date()"<<endl;}~Date(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}public:int_year;protected:int_month;private:int_day;};classTime:publicDate{public:Time(){cout<<"Date()"<<endl;}~Time(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-";cout<<_month<<"-";//cout<<_day<<"-";//派生类中不能访问基类的private成员。cout<<_hour<<"-"<<_minute<<"-"<<_second<<endl;}public:int_hour;protected:int_minute;private:int_second;};
2.public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
voidTest1(){Timet;Datet1;//t=t1;//父类对象不可以给子类对象赋值t1=t;//子类对象不可以给父类对象赋值Time*p1=NULL;Date*p2=NULL;p2=&t;//父类的指针/引用可以指向子类对象//p1=&t1;//子类的指针/引用不能指向父类对象(可以通过强制类型转换完成)t._hour=0;}
3.protetced/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是 has-a 的关系原则。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能访问)。
classDate{public:Date(){cout<<"Date()"<<endl;}~Date(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}public:int_year;protected:int_month;private:int_day;};classTime:protectedDate{public:Time(){cout<<"Date()"<<endl;}~Time(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-";cout<<_month<<"-";//cout<<_day<<"-";cout<<_hour<<"-"<<_minute<<"-"<<_second<<endl;}public:int_hour;protected:int_minute;private:int_second;};voidtest2(){Timet;t._year=0;t._month=0;//不能在外界访问父类的公有成员和保护成员。t._hour=0;}
5.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6.继承体系中的作用域
(1).继承体系中基类和派生类都有独立的作用域。
(2).子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏
classDate{public:Date(){cout<<"Date()"<<endl;}~Date(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}public:int_year;protected:int_month;private:int_day;};classTime:protectedDate{public:Time(){cout<<"Date()"<<endl;}~Time(){cout<<"~Date()"<<endl;}voidDisplay(){Date::Display();//可以通过这样的方式访问cout<<_hour<<"-"<<_minute<<"-"<<_second<<endl;}public:int_hour;protected:int_minute;private:int_second;};voidtest3(){Timet;t.Display();//在外部调用,调用的是父类的函数}
三.派生类的成员函数
在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。且会调用父类的构造函数。
classDate{public:Date(){cout<<"Date()"<<endl;}~Date(){cout<<"~Date()"<<endl;}voidDisplay(){cout<<_year<<"-"<<_month<<"-"<<_day<<endl;}public:int_year;protected:int_month;private:int_day;};classTime:protectedDate{public:voidDisplay(){Date::Display();cout<<_hour<<"-"<<_minute<<"-"<<_second<<endl;}public:int_hour;protected:int_minute;private:int_second;};voidtest3(){·Timet;00182A9Dleaecx,[t]00182AA0callTime::Time(01813FCh)//通过汇编代码看出调用了构造函数00182AA5movdwordptr[ebp-4],0t.Display();}
四.菱形继承与虚继承
从上面经典的菱形继承可以看出,C类里面保存了两份A类的值,在空间上造成了冗余浪费,且访问时,要显示指定访问哪个父类的成员。
classA{public:A(intdata=0):_a(data){}//private:int_a;};classB1:publicA{public:B1(intdata=0):_b1(data){}private:int_b1;};classB2:publicA{public:B2(intdata=0):_b2(data){}private:int_b2;};classC:publicB1,publicB2{public:C(intdata=0):_c(data){}voidfun(){//_a=0;//指示不明确。B1::_a=1;B2::_a=2;}private:int_c;};
虚继承在继承方式前加关键字virtual,它解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。