继承与多态
2015-09-20 17:15
253 查看
继承:
保护已有类的特性而构造新类的过程称为继承
在已有类的基础上新增自己的特性而产生新类的过程称为派生
被继承的已有类称为基类(或父类);
派生出的新类称为派生类(或子类);
继承的目的:实现代码重用
派生的目的:当新的问题出现,原有程序无法解决时,需要对原有程序进行改造
三种继承方式:
公有继承,
私有继承,
保护继承。
1:当基类有默认构造函数时,当创建派生类的对象时,派生类的构造函数会自动调用基类的构造函数
2:当激烈没有默认构造函数时,派生类的构造函数必须使用初始化参数列表来调用基类的构造函数
3:在构造子类对象时,先执行父类构造对象,然后执行参数类的构造函数,最后执行子类构造函数。
例:
赋值兼容规则:
派生类对象可以赋值给基类对象 (比如要动物我们可以给猴子)
派生类对象可以初始化基类引用
派生类对象的地址可以赋值给指向基类的指针(放动物的地方我们可以放猴子)
多态:
c++多态是通过虚函数实现的,虚函数允许子类重新定义成员函数,而子类重写定义弗雷接口的做法成为覆盖或重写
子类需要公有继承父类
定义父类的指针或引用,然后通过指针或引用去调用相应的虚函数
虚函数:
成员函数之前加上virtual 关键字,就是虚成员函数。
判断是否为虚函数:
1:该函数与基类的虚函数有相同的函数名
2:该函数与基类的虚函数有相同的残苏个数与对应的参数类型
3:该函数与基类虚函数有相同的返回值或者满足赋值兼容规则的指针,引用的返回值
多态与非多态区别:
区别就是地址是早绑定还是晚绑定,如果函数的调用在编译期间就可以确定函数的调用地址,并产生代码,就是静态的也就是早绑定是非多态的。而如果函数的调用地址不能在编译期间确定,需要在运行时才确定,这就是晚绑定也称动态联编,是多态的
重载与重写区别:
重载overload:函数名相同,参数列表不同,在同类内部存在,不以返回值判断
重写overwrrte:也称为覆盖,子类重新定义父类中的同名函数。函数特征相同,单数具体实现不同,基类的函数要有关键字virtual,主要是在继承关系中出现。
组合和继承:
组合是has,继承是is,比如眼睛,猴子适合于组合,而动物,猴子适合用继承。
虚拟继承:
沙发:可以看电视,有重量
床:可以睡觉,有重量
沙发床:继承沙发和床,既可以睡觉,又可以看电视
sleeper_sofa:public bed,public sofa
//出错,沙发床不能有两个重量
所以先把重量定义为一类,然后沙发和床都虚拟继承该类。
构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:
1:任何虚拟基类的构造函数按照它们被继承的顺序构造
2:任何非虚拟基类的构造函数按照它们被继承的顺序构造;
3:任何成员对象的构造函数按照它们声明的顺序调用;
4:类自己的构造函数。
保护已有类的特性而构造新类的过程称为继承
在已有类的基础上新增自己的特性而产生新类的过程称为派生
被继承的已有类称为基类(或父类);
派生出的新类称为派生类(或子类);
继承的目的:实现代码重用
派生的目的:当新的问题出现,原有程序无法解决时,需要对原有程序进行改造
三种继承方式:
公有继承,
私有继承,
保护继承。
1:当基类有默认构造函数时,当创建派生类的对象时,派生类的构造函数会自动调用基类的构造函数
2:当激烈没有默认构造函数时,派生类的构造函数必须使用初始化参数列表来调用基类的构造函数
3:在构造子类对象时,先执行父类构造对象,然后执行参数类的构造函数,最后执行子类构造函数。
例:
#include<iostream> using namespace std; class Father { protected: int f_data; public: Father(int x):f_data(x){} Father(){f_data=1;} }; class Son:public Father <span style="color:#ff6666;"> </span><span style="color:#ff0000;"> //以public继承</span> { private: int s_data; public: Son(int x):s_data(x){} Son(){s_data=11;} void show() { cout<<"f_data:"<<f_data<<endl; <span style="color:#ff0000;">//打印继承父类的id</span> cout<<"s_data:"<<s_data<<endl; } }; int main() { Son s1; s1.show(); return 0; }
赋值兼容规则:
派生类对象可以赋值给基类对象 (比如要动物我们可以给猴子)
派生类对象可以初始化基类引用
派生类对象的地址可以赋值给指向基类的指针(放动物的地方我们可以放猴子)
#include<iostream> using namespace std; class A { public: void show() { cout<<"A"<<endl; } }; class B:public A { public: void show() { cout<<"B"<<endl; } }; class C:public B { public: void show() { cout<<"C"<<endl; } }; void fun(A* ptr) { ptr->show(); } int main() { A a1,*p; <span style="color:#ff0000;">//通过指针指向,指针首先指向其继承部分,所以一直打印:A</span> B b1; C c1; p=&a1; fun(p); <span style="color:#ff0000;"> //显示为:A</span> p=&b1; fun(p); <span style="color:#ff0000;">//显示为:A</span> p=&c1; fun(p); <span style="color:#ff0000;"> //显示为:A</span> return 0; }
多态:
c++多态是通过虚函数实现的,虚函数允许子类重新定义成员函数,而子类重写定义弗雷接口的做法成为覆盖或重写
子类需要公有继承父类
定义父类的指针或引用,然后通过指针或引用去调用相应的虚函数
虚函数:
成员函数之前加上virtual 关键字,就是虚成员函数。
判断是否为虚函数:
1:该函数与基类的虚函数有相同的函数名
2:该函数与基类的虚函数有相同的残苏个数与对应的参数类型
3:该函数与基类虚函数有相同的返回值或者满足赋值兼容规则的指针,引用的返回值
#include<iostream> using namespace std; class A { public: virtual void show() <span style="color:#ff0000;">//虚成员函数</span> { cout<<"A"<<endl; } }; class B:public A { public: void show() <span style="color:#ff0000;">//虚成员函数</span> { cout<<"B"<<endl; } }; class C:public B //虚成员函数 { public: void show() { cout<<"C"<<endl; } }; void fun(A* ptr) { ptr->show(); } int main() { A a1,*p; <span style="color:#ff0000;">//通过虚函数,重写父函数</span> B b1; C c1; p=&a1; fun(p); <span style="color:#ff0000;"> //显示为:A</span> p=&b1; fun(p); <span style="color:#ff0000;">//显示为:B</span> p=&c1; fun(p); <span style="color:#ff0000;"> //显示为:C</span> return 0; }
多态与非多态区别:
区别就是地址是早绑定还是晚绑定,如果函数的调用在编译期间就可以确定函数的调用地址,并产生代码,就是静态的也就是早绑定是非多态的。而如果函数的调用地址不能在编译期间确定,需要在运行时才确定,这就是晚绑定也称动态联编,是多态的
重载与重写区别:
重载overload:函数名相同,参数列表不同,在同类内部存在,不以返回值判断
重写overwrrte:也称为覆盖,子类重新定义父类中的同名函数。函数特征相同,单数具体实现不同,基类的函数要有关键字virtual,主要是在继承关系中出现。
组合和继承:
组合是has,继承是is,比如眼睛,猴子适合于组合,而动物,猴子适合用继承。
虚拟继承:
沙发:可以看电视,有重量
床:可以睡觉,有重量
沙发床:继承沙发和床,既可以睡觉,又可以看电视
sleeper_sofa:public bed,public sofa
//出错,沙发床不能有两个重量
所以先把重量定义为一类,然后沙发和床都虚拟继承该类。
#include<iostream> using namespace std; class Furniture { int weight; public: Furniture(){cout<<"Furniture()"<<endl;} ~Furniture(){cout<<"~Furniture()"<<endl;} void setweight(int x) { weight=x; } void getweight() { cout<<weight<<endl; } }; class Sofa:<span style="background-color: rgb(255, 204, 0);">virtual</span> public Furniture { public: Sofa(){cout<<"Sofa()"<<endl;} ~Sofa(){cout<<"~Sofa()"<<endl;} void watch_tv() { cout<<"watch_tv"<<endl; } }; class Bed:<span style="background-color: rgb(255, 255, 0);">virtual</span> public Furniture { public: Bed(){cout<<"Bed()"<<endl;} ~Bed(){cout<<"~Bed()"<<endl;} void sleep() { cout<<"sleeping"<<endl; } }; class Sleepersofa:public Bed,public Sofa { public: Sleepersofa(){cout<<"Sleepersofa()"<<endl;} ~Sleepersofa(){cout<<"~Sleepersofa()"<<endl;} void Foldout() { cout<<"Fold out the sofa"<<endl; } }; int main() { Sleepersofa s1; s1.setweight(20); s1.getweight(); cout<<endl; } skywalker@skywalker:~/item$ ./a.out <span style="white-space:pre"> <span style="color:#cc0000;"> </span></span><span style="color:#cc0000;">//结果如下</span> Furniture() Bed() Sofa() Sleepersofa() 20 ~Sleepersofa() ~Sofa() ~Bed() ~Furniture()
构造对象的规则需要扩展以控制多重继承。构造函数按下列顺序被调用:
1:任何虚拟基类的构造函数按照它们被继承的顺序构造
2:任何非虚拟基类的构造函数按照它们被继承的顺序构造;
3:任何成员对象的构造函数按照它们声明的顺序调用;
4:类自己的构造函数。
相关文章推荐
- Android中正确获得View控件的宽和高——使用篇
- 如何绘制方形渐开线
- 上千个主分片--Kagillion Shards--es横向扩展设计
- 版本控制系统(VCS→DVCS)
- The Balance 1709 (母函数 技巧(相加和相减)) 好题
- Activity,intent,bundle,请求码,结果码,服务,广播
- VBend、unload、exit sub、 end sub、close、hide的比较
- 《大道至简》第一章读后感
- 学习日志---动态规划(背包问题)
- Codeblocks的编译器配置
- Servlet读取资源文件的三种方式
- 实现顶部轮播,下部listview经典布局的两种方式
- 主分片平衡--Shard Overallocation--es横向扩展设计
- Crisis of HDU(母函数)
- 表驱动法
- 2015 ACM-ICPC 沈阳网络赛总结
- sublime安装与配置
- iOS开发笔记--UISlider的相关属性设置
- docker学习笔记(一)
- Move Zeroes——Leetcode