C++继承
2016-03-09 01:35
309 查看
在定义对象时,可以发现很多对象都是有联系的,如以下的两个类,worker中的一些成员也是person的成员,应对这种情况,减轻程序员的工作量,C++设计了继承。
有了继承,我们可以把worker的类写成这样,不用再把person类中已有的成员再写一遍。worker是person的派生类,person是worker的基类。
Person();
Worker();
~Worker();
~Person();
C++的继承方式有三种。
class A: public B //公有继承
class A:protected B//保护继承
class A:private B//私有继承
protected在不涉及继承时,特性和private的性质是一样的。
当在继承时,作如下定义。
那么相关的对象成员会继承到如下位置。其中void work()能够访问继承来的m_iAge。
private的继承特性,如果将protected改为private。代码如下。
保护继承,基类的public和protected的成员都会被继承到派生类的protected下面,而private还是无法被访问。
私有继承,基类的public和protected的成员都会被继承到派生类的private下面,而private还是无法被访问。
C++有两个很容易混淆的概念,覆盖和隐藏。什么是隐藏,加入B是A的派生类,两个类有相同函数名的成员函数,比如void ABC(),这时,子类中的void ABC()会自动隐藏父类中的void ABC(),但并没有消失,可以通过特殊的手段访问,数据成员也有隐藏这种现象。
在继承中,派生类的对象可以复制给基类,也可以用基类的指针指向派生类的对象,反之不可以。但基类还是无法访问子类中特有的成员函数和成员数据。如果销毁时,只调用了基类的析构函数,而没有调用派生类的,那么就会有一些内存没有删干净。为了防止这种现象,就会用到虚析构函数。
当有继承关系时,用父类的指针指向堆中子类对象,并且想用父类的指针来释放掉这块内存,那么要用到虚析构函数,那么在释放内存时,会依次调用子类的析构和父类的析构函数。
多重继承,比如有三个类,人类-士兵类-步兵类,三个依次继承,那么就成为多重继承。
多继承,如果有一个类有多个基类,如农民工类集成了农民类和工人类。
在实际中,会出现菱形继承的情况,就是D继承了B和C类,B和C都是A的派生类,既包含了多继承又包含了多重继承,我们在实例化D,就会继承两个A的成员,造成数据的冗余,为了解决这种现象,就用虚继承的方式。如果B和C是虚继承A的话,那么实例化D后,D中只有一份A的数据成员,不会冗余。
当我们在基类定义时加上virtual时,那么继承的农民工类在实例化时,就只有一份person的数据了。
重定义,就是指在当前的工程中,一个类被定义了两遍,只在多个继承类的.h文件中,多次引用了 基类.h的文件,这就出现了重定义。通过宏定义解决重定义。
首先,在公共继承的类中增加宏定义。在菱形继承中,重定义必然会出现。
class Person { public: void eat(); string m_strName; int m_iAge; }; class Worker { public: void eat(); void work(); string m_strName; int m_iAge; int m_iSalary; };
有了继承,我们可以把worker的类写成这样,不用再把person类中已有的成员再写一遍。worker是person的派生类,person是worker的基类。
class Worker:public Person { public: void work(); int m_iSalary; };当我们实例化一个派生类的对象时,会先构造基类,再构造派生类,而析构时顺序相反,运行的顺序如下。
Person();
Worker();
~Worker();
~Person();
C++的继承方式有三种。
class A: public B //公有继承
class A:protected B//保护继承
class A:private B//私有继承
protected在不涉及继承时,特性和private的性质是一样的。
class Person { public: Person();//构造函数 ~Person();//析构函数 void eat(); protected: int m_iAge; private: string m_strName; };当做如下访问时,会出现错误。因为不在public下面。
int main() { Person person; person.eat(); person.m_iAge = 20;//错误 person.m_strName = "jim";//错误 return 0; }
当在继承时,作如下定义。
class Person { public: Person();//构造函数 ~Person();//析构函数 void eat(); protected: int m_iAge; string m_strName; };
那么相关的对象成员会继承到如下位置。其中void work()能够访问继承来的m_iAge。
class Worker :public Person//公有继承 { public: Worker();//构造 ~Worker();//析构 void eat();//继承person的 void work(){ m_iAge = 20; } protected: string m_strName;//继承person int m_iAge;//继承person int m_iSalary; };
private的继承特性,如果将protected改为private。代码如下。
class Person { public: Person();//构造函数 ~Person();//析构函数 void eat(); private: int m_iAge; string m_strName; }; class Worker :public Person//公有继承 { public: Worker();//构造 ~Worker();//析构 void eat();//继承person的 void work(){ m_iAge = 20; }//这样访问错误 protected: //private中的m_strName和m_iAge被继承到了不可见位置 int m_iSalary; };
保护继承,基类的public和protected的成员都会被继承到派生类的protected下面,而private还是无法被访问。
私有继承,基类的public和protected的成员都会被继承到派生类的private下面,而private还是无法被访问。
C++有两个很容易混淆的概念,覆盖和隐藏。什么是隐藏,加入B是A的派生类,两个类有相同函数名的成员函数,比如void ABC(),这时,子类中的void ABC()会自动隐藏父类中的void ABC(),但并没有消失,可以通过特殊的手段访问,数据成员也有隐藏这种现象。
在继承中,派生类的对象可以复制给基类,也可以用基类的指针指向派生类的对象,反之不可以。但基类还是无法访问子类中特有的成员函数和成员数据。如果销毁时,只调用了基类的析构函数,而没有调用派生类的,那么就会有一些内存没有删干净。为了防止这种现象,就会用到虚析构函数。
当有继承关系时,用父类的指针指向堆中子类对象,并且想用父类的指针来释放掉这块内存,那么要用到虚析构函数,那么在释放内存时,会依次调用子类的析构和父类的析构函数。
class Person { public: Person();//构造函数 virtual ~Person();//析构函数 void play(); private: int m_iAge; string m_strName; };
多重继承,比如有三个类,人类-士兵类-步兵类,三个依次继承,那么就成为多重继承。
class Person {}; class Soldier :public Person {}; class Infantryman :public Soldier {};
多继承,如果有一个类有多个基类,如农民工类集成了农民类和工人类。
class Worker {}; class Farmer {}; class MigrantWorker:public Worker,public Farmer {};
在实际中,会出现菱形继承的情况,就是D继承了B和C类,B和C都是A的派生类,既包含了多继承又包含了多重继承,我们在实例化D,就会继承两个A的成员,造成数据的冗余,为了解决这种现象,就用虚继承的方式。如果B和C是虚继承A的话,那么实例化D后,D中只有一份A的数据成员,不会冗余。
class Worker :virtual public Person// 虚基类 {}; class Farmer :virtual public Farmer {};
当我们在基类定义时加上virtual时,那么继承的农民工类在实例化时,就只有一份person的数据了。
重定义,就是指在当前的工程中,一个类被定义了两遍,只在多个继承类的.h文件中,多次引用了 基类.h的文件,这就出现了重定义。通过宏定义解决重定义。
首先,在公共继承的类中增加宏定义。在菱形继承中,重定义必然会出现。
#ifndef PERSON_H #define PERSON_H /*******文件体************/ #endif
相关文章推荐
- LeetCode 234. Palindrome Linked List
- C语言实现通讯录
- C语言注释与C++注释的相互转换
- C++ 公有继承简析
- c/C++
- C++第一次上机实验
- C++的字面值和字面值类型
- ubuntu配置vim为windows下C++编程风格
- 深入学习C++.2016_3_8
- C++学习之静态成员
- OpenJudge百炼习题解答(C++)--题2690:首字母大写
- C语言的精髓-指针
- 杭电oj 1108 最小公倍数
- C++ 中dynamic_cast<>的使用方法
- Java与C++的析构函数
- 提高C++程序运行效率的10个简单方法
- C++中字面值常量和字面值类型
- C++第一次上机实验报告—01
- 理解C语言——从小菜到大神的晋级之路(13)——进一步讨论函数与指针
- 我的第一次C++试验