继承和多态
一继承和多态
1总结:类和对象:体现了OOP封装和隐藏的思想
2.继承:体现了OPP的代码的复用和重用
3.组合:一个类定义对象是另一个类的成员对象 a part of ....
4继承:一个类的定义:[ 访问限定符] 已定义的过的类 a kind of ....
二.派生类继承什么东西
1.派生类继承了和基类除了构造函数和析构函数外的所有成员
基类的名字和派生类的名字相同是因为派生类还继承了类的作用域
2派生类中继承的基类成员的访问限定
继承方式 基类的访问限定 派生类访问限定 外部访问限定
public public 可以
公有继承 private 不可见 可继承 不可以
protected protected 不可以
public protected 不 可以
保护有继承 private 不可见 可继承 不可以
protected protected 不可以
public privite 不 可以
公有继承 private 不可见 可继承 不可以
protected privite 不可以t
3.private 和protecde 有什么区别
基类的privite的成员在派生类中不可见 不可访问,且外部也不能访问
基类的protected的成员在派生类中可访问,且外部也不能访问
4.不加继承方式的继承是什么方式
class此时默认的是私有继承structt默认的为公有继承
三 派生类的构造过程
1先构造基类的部分,在构造派生类的,出作用域,先析构派生类,在析构基类
2在派生类的构造函数的初始化列表当中,指定基类部分的构造函数,不指名的话,基类就要调用默认的构造
例子:如果派生类没有定义构造函数,就调用基类的构造函数
class Base
{
public:
Base(int data) :ma(data) { cout << "Base()" << endl; }
~Base() { cout << "~Base()" << endl; }
void show() { cout << "Base::show()" << endl; }
void show(int val) { cout << "Base::show(int)" << endl; }
protected:
int ma;
};
class Derive : public Base
{
public:
//“Base”: 没有合适的默认构造函数可用
Derive(int data = 20) :mb(data), Base(data)//注意这里不能写ma(data)
{
cout << "Derive()" << endl;
}
~Derive() { cout << "~Derive()" << endl; }
/*void show()
{
cout << "Derive::show()" << endl;
//this->Base::show(); //派生类的同名方法中调用基类的同名方法
}*/
private:
int mb;
};
int main()
{
Derive d1;
d1.show(); // Base::
//d1.Base::show();
d1.show(10);//“Derive::show”: 函数不接受 1 个参数
return 0;
}
结果
Base()
Derive()
Base::show()
Base::show(int)
~Derive
~Base()
3基类和派生类同名方法之间的关系
(1)重载;
函数名相同,参数列表不同
作用域相同
(2)隐藏
隐藏必须出现在继承结构中
派生类和基类的方法名字相同,此时派生类只调用派生类的方法
class Base
{
public:
Base(int data) :ma(data) { cout << "Base()" << endl; }
~Base() { cout << "~Base()" << endl; }
void show() { cout << "Base::show()" << endl; }
void show(int val) { cout << "Base::show(int)" << endl; }
protected:
int ma;
};
class Derive : public Base
{
public:
//“Base”: 没有合适的默认构造函数可用
Derive(int data = 20) :mb(data), Base(data)//注意这里不能写ma(data)
{
cout << "Derive()" << endl;
}
~Derive() { cout << "~Derive()" << endl; }
void show()
{
cout << "Derive::show()" << endl;
//this->Base::show(); //派生类的同名方法中调用基类的同名方法
}
private:
int mb;
};
int main()
{
Derive d1;
d1.show(); // Base::
//d1.Base::show();
//d1.show(10);//“Derive::show”: 函数不接受 1 个参数
return 0;
}
结果:
Base()
Derive()
Derive::show()
~Derive
~Base()
、、、、、、、、、、、、、、、、
(3)重写、覆盖
在继承结构中,基类的方法和派生类的方法返回值,函数名,成员列表都相同,而且基类的函数是虚函数,那么派生类的函数也叫作虚函数,那么派生类的虚函数也叫重写、覆盖,
4.继承结构中,从上到下 从下到上的转换关系
(1)基类对象赋值给子类对象 不可以
(2)子类对象赋值给基类对象 可以
总结.只能从下向上转换
(3)基类指针指向子类对象 可以
(4)子类指针指向基类对象 不 可以
5.虚函数
基类成员方法的返回值前加了vitual 关键字
在继承结构中,基类的方法和派生类的方法返回值,函数名,成员列表都相同,而且基类的函数是虚函数,那么派生类的函数也叫作虚函数,那么派生类的虚函数也叫重写、覆盖,
虚函数表:
6. 静态函数的绑定和动态组合
静态绑定:指定在编译时期的绑定,函数调用在编译时期就确定了;
动态绑定:在运行时期的绑定,通过寻找虚函数指针,找到虚函数表 再找到虚函数地址,进行调用,这都是发生在运行阶段
隐藏到底隐藏什么?覆盖就覆盖什么?
隐藏就是派生类的作用域把基类的作用域给隐藏了表中,
覆盖是在派生类的虚函数用派生类重写虚函数把基类继承来的虚函数的地址给覆盖了,
例子
没有虚函数
#include <iostream>
#include <typeinfo> // typeid(name).name()
using namespace std;
class A
{
public:
A(int data) :ma(data) {}
void show() { cout << "A::show ma:" << ma << endl; }
protected:
int ma;
};
class B : public A
{
public:
B(int data) : mb(data), A(data) {}
void show() { cout << "B::show ma:" << ma << " mb:" << mb << endl; }
private:
int mb;
};
int main()
{
A a(10);
B b(20);
A *p = &b;
p->show(); // Derive 自己的成员+基类::成员 A::show
/*
show是普通函数,在这里是静态绑定
call A::show
*/
//派生类对象的内存大小 8
cout << sizeof(b) << endl;
//指针的类型 A* A*
cout << typeid(p).name() << endl;
//指针指向对象的类型 A B 不能识别静态类型了 p的类型里面有虚函数=》RTTI
cout << typeid(*p).name() << endl;
return 0;
}
结果:
A::show ma :20 mb:20
8
class A*
class A
有虚函数
class A
{
public:
A(int data) :ma(data) {}
virtual void show() { cout << "A::show ma:" << ma << endl; }
protected:
int ma;
};
class B : public A
{
public:
B(int data) : mb(data), A(data) {}
void show() { cout << "B::show ma:" << ma << " mb:" << mb << endl; }
private:
int mb;
};
int main()
{
A a(10);
B b(20);
A *p = &b;
p->show(); // Derive 自己的成员+基类::成员 B::show
/*
show是虚函数,在这里就要动态绑定/运行时期的绑定了
mov eax, dword ptr[p]
mov ecx, dword ptr[eax]
call ecx
*/
//派生类对象的内存大小 12
cout << sizeof(b) << endl;
//指针的类型 A* A
cout << typeid(p).name() << endl;
//指针指向对象的类型 A B 不能识别静态类型了 p的类型里面有虚函数=》RTTI
cout << typeid(*p).name() << endl;
return 0;
}
结果:
B::show ma :20 mb:20
12
class A*
class B
7.什么叫RTTI?RTTI run-time type informaition 运行时的类型的识别
RTTI存在虚函数表中:当一个类有虚函数,它编译的时候产生一个Vtable ,虚函数表存放了虚函数的地址,Vptr 相对内存起始地址的偏移量,以及RTTI指针(和类型一一对应)