面向对象c++之继承

来源:互联网 发布:mysql over 函数 编辑:程序博客网 时间:2024/06/10 02:36

面向对象三大机制包括:

1.封装,隐藏内部实现。

2.继承,复用现有代码。(面向对象最显著的特征)

3.多态,改写对象行为。

继承,是一种复用的手段。是从先辈处得到属性和行为特征。类的继承就是新的类从已

的类那里得到已有的特征。

类成员的访问限定有三种:public,protected,private,在类外可以访问类的公有成员,

私有和保护都不可以访问。代码举例:

#include<iostream>using namespace std;class A{public:A():_pub(1),_pro(2),_pri(3){}public:int _pub;protected:int _pro;private:int _pri;};int main(){A a;cout << a._pub << endl;cout << a._pro << endl;cout << a._pri << endl;system("pause");return 0;}


代码编译不通过,提示不可访问类的私有和保护成员。

也有3种继承关系:public(公有继承),protected(保护继承),private(私有继承)

那么父类成员在子类中的访问属性究竟会是怎样的呢?


【总结】在继承机制下,无论哪种继承方式,子类中可以访问父类的公有保护成员,

私有成员不可访问;在类外,只能访问公有成员,私有和保护都不可访问。这个可以通

过代码去验证。

类外只能访问类的公有成员。如果一些父类成员不想被父类对象直接访问,但是需

要在派生类中访问,就定义成保护成员。protected成员的特点:“外人”不可访问,“儿

子”可以访问。

class中继承方式默认是private,struct中默认是public。

类与类之间的关系有三种:

1.has-a,一个类的成员是另一个类的对象;私有继承是另一种实现has-a的途径。

2.uses-a,一个类的成员函数的参数是另一个类的对象

3.is-a,公有继承,父类可用的成员对子类也是可用的。

赋值兼容规则:

前提:public继承下。

1.父类对象 = 子类对象

举例:人通过继承得到超人,即超人具备人的特性,当然也有其本身特有的功能。

人 = 超人(超人的特异功能不被赋值)

2.父类对象不可赋值给子类对象。

3.父类指针可以指向子类对象,如图。子类指针不可以指向父类对象。但是可以通过

强制类型转换完成。但是也可能会出现一定的问题。(下边的代码)


4.父类对象的引用可以引用子类对象。(与指针同理)

class B{public:B():_pub(10), _pro(20), _pri(30){cout << "B()" << endl;}void show(){cout << _pub << endl;cout << _pro << endl;cout << _pri << endl;}public:int _pub;protected:int _pro;private:int _pri;};class D:public B{public:D():B()    ,_i(100){cout << "D()" << endl;}void show(int ){cout << _pub << endl;cout << _pro << endl;//cout << _pri << endl;}int _i;};int main(){D d;B b;       D *pd;pd = (D *)&b;//子类对象通过强转指向父类对象pd->_i = 10;       system("pause");return 0;}



运行之后会出现程序崩溃。所以尽量不要强转。

注:创建子类对象时,会先调用父类的构造函数,然后再调用子类的构造函数,结束

时,先调用子类的析构函数,再调用父类的析构函数。若父类没有默认的构造函数,子

类构造函数中对父类成员的初始化必须在初始化列表中实现。

如果子类中有与父类同名的函数或者成员,父类的函数或者成员被隐藏,与函数的参

数,返回值类型都无关。隐藏,父类的函数仍然存在。

举例:

class B{public:B():_b(1){}void Show(){cout << _b << endl;}private:int _b;};class D:public B{public:D():B(),_b(2),_d(3){}void Show(){cout << _b << endl;cout << _d << endl;}private:int _b;int _d;};int main(){B b;D d;b.Show();d.Show();cout << sizeof(b) << endl;cout << sizeof(d) << endl;system("pause");return 0;}


D中有与B同名的成员和函数,所以子类中就会隐藏父类的成员,但是父类的成员依然存

在,b.Show()依然可以打印出B中的成员。b的大小是4字节,d的大小是12字节。这就是

所谓的隐藏。

多重继承:

前边整理的都是都是单继承,即一个类从一个父类派生而来。当一个子类有多个父类

时,这种继承方式成为多重继承。

在多重继承中,最典型的继承方式就是菱形继承。


为了解决菱形继承中出现的问题,我们引入了虚基类。看下边的代码:

class A{public:A():_a(1){}protected:int _a;};class B :virtual public A{public:B():_b(2){}protected:int _b;};class C :virtual public A{public:C():_c(3){}protected:int _c;};class D :public B, public C{public:D():_d(4){}protected:int _d;};int main(){D d;cout << sizeof(d) << endl;system("pause");return 0;}


要是没有在B,C的派生列表中加上virtual关键字,最终输出d的大小是20字节,加上之

后呢就是24字节。

我们知道,如果是单继承的话,子类成员在内存中的情况就是:先是来自父类的成员,

然后就是来自子类的成员,紧挨存储。那么虚继承的对象模型究竟是什么,打开内存看

一下:(windows下的情况)linux下的情况之后补充 。



大家也可以打开内存看单继承和菱形继承的对象模型,这里就不给出了。

友元与继承

由于友元不可以传递,所以友元就不能继承。父类的友元不可以访问子类的私有和保

护成员,但是可以访问子类从父类继承下来的成员。父类的友元要想访问子类,必须将

该友元声明为子类的友元。

class D;class B{friend void Show(B &b,D &d);public:B():_b(1){}protected:int _b;};class D:public B{public:D():_d(4),_e(5),_f(6){}public:int _d;protected:int _e;private:int _f;};void Show(B &b, D &d){cout << b._b << endl;cout << d._b << endl;cout << d._d << endl;//cout << d._e << endl;//cout << d._f << endl;}int main(){B b;D d;Show(b,d);system("pause");return 0;}


父类的友元函数并不能访问子类的私有成员和保护成员。

静态成员与继承

如果父类定义了一个静态成员,则在整个继承体系中都只有该成员的唯一定义,不管

从父类派生出多少子类,对于每个静态成员来说只存在唯一的实例。并且子类的对象都

能访问父类的静态成员。这里就不给出代码了,感兴趣的可以自己写出代码。

原创粉丝点击