您的位置:首页 > 编程语言 > C语言/C++

C++继承

2016-03-09 01:35 309 查看
在定义对象时,可以发现很多对象都是有联系的,如以下的两个类,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;//继承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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: