C++类的继承的基本认识
2016-04-10 22:58
344 查看
一.继承的含义
继承是面向对象复用的重要手段。通过继承定义一个类,它们的类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。
二.继承关系与访问限定符
![](http://s4.51cto.com/wyfs02/M00/7E/D9/wKiom1cKTsvxJcs9AAB4Ghkzajc847.png)
有如下总结:
1.基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保护成员。可以看出保护成员限定符是因继承才出现的。
例如:
2.public继承是一个接口继承,保持is-a原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能访问)。
6.继承体系中的作用域
(1).继承体系中基类和派生类都有独立的作用域。
(2).子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏
在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。且会调用父类的构造函数。
![](http://s2.51cto.com/wyfs02/M00/7E/D6/wKioL1cKXbnQrxfnAAAytiDh7Wg416.png)
从上面经典的菱形继承可以看出,C类里面保存了两份A类的值,在空间上造成了冗余浪费,且访问时,要显示指定访问哪个父类的成员。
![](http://s3.51cto.com/wyfs02/M02/7E/D9/wKiom1cKYe7Sbu2xAAA0j-fX3g0034.png)
继承是面向对象复用的重要手段。通过继承定义一个类,它们的类型之间的关系建模,共享公有的东西,实现各自本质不同的东西。
二.继承关系与访问限定符
![](http://s4.51cto.com/wyfs02/M00/7E/D9/wKiom1cKTsvxJcs9AAB4Ghkzajc847.png)
有如下总结:
1.基类的私有成员在派生类中是不能被访问的,如果一些基类成员不想被基类对象直接访问,但需要在派生类中能访问,就定义为保护成员。可以看出保护成员限定符是因继承才出现的。
例如:
class Date { public: Date() { cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } void Display() { cout << _year << "-" << _month << "-" << _day << endl; } public: int _year; protected: int _month; private: int _day; }; class Time : public Date { public: Time() { cout << "Date()" << endl; } ~Time() { cout << "~Date()" << endl; } void Display() { 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原则,每个父类可用的成员对子类也可用,因为每个子类对象也都是一个父类对象。
void Test1() { Time t; Date t1; //t = t1; //父类对象不可以给子类对象赋值 t1 = t; //子类对象不可以给父类对象赋值 Time* p1 = NULL; Date* p2 = NULL; p2 = &t; //父类的指针/引用可以指向子类对象 //p1 = &t1; //子类的指针/引用不能指向父类对象(可以通过强制类型转换完成) t._hour = 0; }3.protetced/private继承是一个实现继承,基类的部分成员并未完全成为子类接口的一部分,是 has-a 的关系原则。
4. 不管是哪种继承方式,在派生类内部都可以访问基类的公有成员和保护成员,但是基类的私有成员存在但是在子类中不可见(不能访问)。
class Date { public: Date() { cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } void Display() { cout << _year << "-" << _month << "-" << _day << endl; } public: int _year; protected: int _month; private: int _day; }; class Time : protected Date { public: Time() { cout << "Date()" << endl; } ~Time() { cout << "~Date()" << endl; } void Display() { cout << _year << "-"; cout << _month << "-"; //cout<< _day << "-"; cout << _hour << "-" << _minute << "-" << _second << endl; } public: int _hour; protected: int _minute; private: int _second; }; void test2() { Time t; t._year = 0; t._month = 0; //不能在外界访问父类的公有成员和保护成员。 t._hour = 0; }5.使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的写出继承方式。
6.继承体系中的作用域
(1).继承体系中基类和派生类都有独立的作用域。
(2).子类和父类中有同名成员,子类成员将屏蔽父类对成员的直接访问。(在子类成员函数中,可以使用 基类::基类成员 访问)--隐藏
class Date { public: Date() { cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } void Display() { cout << _year << "-" << _month << "-" << _day << endl; } public: int _year; protected: int _month; private: int _day; }; class Time : protected Date { public: Time() { cout << "Date()" << endl; } ~Time() { cout << "~Date()" << endl; } void Display() { Date::Display(); //可以通过这样的方式访问 cout << _hour << "-" << _minute << "-" << _second << endl; } public: int _hour; protected: int _minute; private: int _second; }; void test3() { Time t; t.Display(); //在外部调用,调用的是父类的函数 }三.派生类的成员函数
在继承关系里面,在派生类中如果没有显示定义这六个成员函数,编译系统则会默认合成这六个默认的成员函数。且会调用父类的构造函数。
class Date { public: Date() { cout << "Date()" << endl; } ~Date() { cout << "~Date()" << endl; } void Display() { cout << _year << "-" << _month << "-" << _day << endl; } public: int _year; protected: int _month; private: int _day; }; class Time : protected Date { public: void Display() { Date::Display(); cout << _hour << "-" << _minute << "-" << _second << endl; } public: int _hour; protected: int _minute; private: int _second; }; void test3() { · Time t; 00182A9D lea ecx,[t] 00182AA0 call Time::Time (01813FCh) //通过汇编代码看出调用了构造函数 00182AA5 mov dword ptr [ebp-4],0 t.Display(); }四.菱形继承与虚继承
![](http://s2.51cto.com/wyfs02/M00/7E/D6/wKioL1cKXbnQrxfnAAAytiDh7Wg416.png)
从上面经典的菱形继承可以看出,C类里面保存了两份A类的值,在空间上造成了冗余浪费,且访问时,要显示指定访问哪个父类的成员。
class A { public: A(int data = 0) :_a(data) {} //private: int _a; }; class B1 : public A { public: B1(int data=0) :_b1(data) {} private: int _b1; }; class B2 : public A { public: B2(int data = 0) :_b2(data) {} private: int _b2; }; class C :public B1,public B2 { public: C(int data = 0) :_c(data) {} void fun() { //_a = 0; //指示不明确。 B1::_a = 1; B2::_a = 2; } private: int _c; };虚继承在继承方式前加关键字virtual,它解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
![](http://s3.51cto.com/wyfs02/M02/7E/D9/wKiom1cKYe7Sbu2xAAA0j-fX3g0034.png)
相关文章推荐
- PostgreSQL教程(三):表的继承和分区表详解
- Lua面向对象之类和继承浅析
- 浅析Ruby中继承和消息的相关知识
- 设计引导--一个鸭子游戏引发的设计理念(多态,继承,抽象,接口,策略者模式)
- C++实现不能被继承的类实例分析
- C# 面向对象三大特性:封装、继承、多态
- PHP类的封装与继承详解
- js继承 Base类的源码解析
- Javascript 面向对象 继承
- JavaScript 继承使用分析
- Javascript面向对象编程(二) 构造函数的继承
- Javascript中的几种继承方式对比分析
- javascript面向对象之Javascript 继承
- JavaScript 对象、函数和继承
- 详述JavaScript实现继承的几种方式(推荐)
- javascript 继承学习心得总结
- 学习javascript面向对象 javascript实现继承的方式
- 关于JavaScript的面向对象和继承有利新手学习
- JavaScript 继承详解(一)
- JavaScript 继承详解(二)