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

走进C++程序世界------继承和派生

2013-09-24 23:05 375 查看

继承和派生 

继承是面向对象编程语言的最重要方面之一,正确的使用继承可编写出设计良好,容易于维护和扩展的应用程序。下面是在其他博客中的总结:

******************************以下转载 http://blog.csdn.net/caijp1090/article/details/7484906******************

1、继承:保持已有类的特性而构造新类的过程;派生:在已有类的基础上新增自己的特性而产生新类的过程。

2、访问控制

   a、公有继承public:基类的public和protected成员的访问属性在继承类中保持不变,但基类的private成员不可访问;派生类的成员可以直接访问基类的public和protected成员,但是不能访问基类的private成员;通过派生类的对象只能访问基类的public成员

   b、私有继承private:基类的public和protected成员都以private身份出现在派生类中,但基类的private成员不可以访问; 派生类中的成员函数直接访问基类中的public和protected成员,但不能访问基类的private成员;通过派生类的对象不能访问基类中的任何成员。

  c、保护继承protected:基类的public和protected成员都以protected身份出现在派生类中,但基类的private成员不可访问;派生类的成员函数可以直接访问基类中的punlic和protected成员,但不能访问基类的private成员;派生类的对象不能访问基类中的任何成员。

3、protected成员特点:对于建立其所在类对象来说,他与private成员性质相同;对于其派生类来说,与public成员性质相同,既实现了数据隐藏又方便继承,实现代码重用。

4、基类与派生类的对应关系

 a、单继承:派生类只从一个基类派生

 b、多继承:派生类从多个基类派生==》class派生类名:继承方式1  基类名1,继承方式2  基类名2,......

 c、多种派生:有一个基类派生出多个不同的派生类

 d、多层派生:派生类又作为基类,继承派生新的类

5、派生类的构造、析构函数

 a、基类的构造函数不被继承,需要在派生类中自行声明,声明构造函数时,只需要对本类中新增成员进行初始化,对继承来的基类成员的初始化由基类完成。

      ==》单一继承时的构造函数:派生类名::派生类名(基类所需要的形参,本来成员所需要的形参):基类名(参数){本类成员初始化}

      ==》多继承时的构造函数:派生类名::派生类名(基类1形参,基类2形参,...基类n形参,本类形参):基类名1(参数)...基类名n(参数){本类成员初始化}

       当基类中声明有缺省形式的构造函数或未声明构造函数时,派生类构造函数的声明中可以省略对基类构造函数调用;若基类中未声明构造函数,派生类中也可以不声明,全采用缺省形式构造函数;当基类声明有带形参的构造函数时,派生类也应声明带形参的构造函数,提供将参数传递给基类构造函数的途径。

     ==》多继承且有内嵌对象时的构造函数:派生类名::派生类名(基类1形参,基类2形参,...基类n形参,本类形参):基类名1(参数)...基类名n(参数),派生类对象数据成员的初始化{本类成员初始化}

     构造函数的次序:调用基类构造函数,调用顺序按照他们被继承时声明的顺序(从左到右)--->调用成员对象的构造函数,调用顺序按照他们在类中声明的顺序--->派生类的构造函数体中的内容

  b、继承时的析构函数

      析构函数也不被继承,派生类自行声明;声明方法与一般(无继承关系时)类的析构函数相同;不需要显式地调用基类的析构函数,系统会自动隐式调用;调用次序与构造函数相反。相当于栈。

6、派生类成员的标识与访问

  a、同名覆盖原则:当派生类与基类中有相同成员时,若未强行指名,则通过派生类对象使用的是派生类中的同名成员,如要通过派生类对象访问基类中被覆盖的同名成员应使用基类名限定

  b、在多继承时,基类与派生类之间,或基类之间出现同名成员时,将出现访问时的二义性(不确定性),采用虚函数或者支配(同名覆盖)原则解决。

  c、在派生类从多个基类派生,而这些基类又从同一个基类派生,则在访问此共同基类中成员时,将产生二义性,采用虚基类来解决。

7、虚基类

   用于有共同基类的场合,以virtual修饰说明基类,主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题,为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝。但在第一次继承时就要将共同基类设计为虚基类,从而没有多次拷贝解决冗余的情况。

8、虚基类及其派生类构造函数

    a、建立对象时所指定的类称为最(远)派生类

    b、虚基类的成员是由最(远)派生类的构造函数通过调用虚基类的构造函数进行初始化的

    c、在整个继承结构中,直接或间接继承虚基类的所有派生类,都必须在构造函数的成员初始化表中给出对虚基类的构造函数的调用,如果未列出,则表示调用该虚基类的缺省构造函数。

    d、在建立对象时,只有最(远)派生类的构造函数调用虚基类的构造函数,该派生类的其他基类对虚基类构造函数的调用被忽略。

9、赋值兼容原则

一个公有派生类的对象在使用上可以被当作基类的对象,反之则禁止,具体表现在:

    a、派生类的对象可以被赋值给基类对象

    b、派生类的对象可以初始化基类的引用

    c、指向基类的对象的指针也可以指向派生类

************************************************************************************************************************************************
/*
*derive.cpp
*Date : 2013-9-24
*Author: sjin
*Mail:413977243@qq.com
*/
#include <iostream>
using namespace std;

/*三种访问限定符:
* 公有(public),保护(protected)和私有(private)
*  如果在函数中声明了一个对象,则它可以访问所有的共有成员
*  数据和函数。而成员函数可以访问其所属类的私有数据成员和
*  函数。也可以访问任何从其所属类派生而来的类的保护数据成员
*  和函数。
*/
/*定义一个枚举类型结构*/
enum BREED{
GOLDEN,
CAIRN,
DANDIE,
SHETLAND,
DOBERMAN,
LAB
};

class Manmal{
public:
Manmal():itsAge(2),itsWeight(5){ cout << " create Manmal object..."<<endl;}
~Manmal(){cout << " destroy Manmal object..."<<endl;}

/*inline 函数写法*/
int GetAge()const{ return itsAge;}
void SetAge(int age){itsAge = age;}
int GetWeight()const{ return itsWeight;}
void SetWeight(int weight){itsWeight = weight;}

//other methods
void Speak()const { cout << "Manmal sound!\n";}
void Sleep()const { cout << "shh,I am Sleeping.\n";}

private:
int itsAge;
int itsWeight;
};

class Dog : public Manmal {
public:
Dog():itsBread(GOLDEN){cout << " create Dog object..." << endl;}
~Dog(){cout << " destroy Dog object..."<< endl;}

BREED GetBread() const {return itsBread;}
void SetBread(BREED breed) { itsBread = breed;}

void WagTail() const { cout << "Tail wagging..\n";}
void BegForFood() const { cout << "Begging for food..\n";}

private:/*私有类型,只能有内部补函数调用*/
BREED itsBread;

};
/*Manmal类是基类,Dog类是Manmal类的派生类
* 所有的dog对象都有年龄、体重和品种。是从Manmal类继生而来的
* */

int main()
{
/*声明一个dog对象:Fido,它继承了Manmal的所有属性,同时具有
* Dog的所有属性。*/
Dog Fido;
Fido.Speak();
Fido.WagTail();
cout << "Fido is "<< Fido.GetAge() << "years old" << endl;
return 0;
}

[jsh@localhost class]$ g++ derive.cpp
[jsh@localhost class]$ ./a.out
create Manmal object...
create Dog object...
Manmal sound!
Tail wagging..
Fido is 2years old
destroy Dog object...
destroy Manmal object...



总结:通过上面的输出,我们可以了解到继承和派生的用法。还有关于构造函数和析构函数在创建和函数退出时的调用情况。创建派生类对象时,总是先调用基类的构造函数,再调用派生类的构造函数,函数退出时,正好相反,先调用派生类的析构函数,再调用基类的析构函数。

    关于析构函数或者构造函数的继承性:

 依照上面的示例进行说明:创建Fido时,首先调用基类的构造函数,创建一个Manmal对象,然后调用Dog的构造函数创建DOG对象。在FISo创建好之前,它是不存在的,这就意味着必须创建其Manmal部分和 Dog部分。因此必须调用这两个类的构造函数。Fido被销毁时,首先调用Dog的析构函数,然后为Fido的Manmal的析构函数。每个析构函数对对应了对应部分销毁后的执行工作的机会,所以说构造函数和析构函数都是必须要执行。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  继承 派生