C++继承

来源:互联网 发布:韩子高网络剧下百度云 编辑:程序博客网 时间:2024/05/29 19:00

在定义对象时,可以发现很多对象都是有联系的,如以下的两个类,worker中的一些成员也是person的成员,应对这种情况,减轻程序员的工作量,C++设计了继承。

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;//继承personint m_iAge;//继承personint 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


0 0