C++笔记记录Ⅲ 继承与多态
>ㅂ< 开学啦上课啦 更一点啦
就从刚上的记起。。。
-----------------------------------------------------------------
面向对象语言四大特点:抽象 封装 继承 多态
类和类之间基本关系:组合代理继承
类:封装和隐藏。
模板:对类型进行参数化。
运算符重载:对象的运算和基本类型的运算一致。
继承:代码的复用。
-----------------------------------------------------------------
class Base//基类sizeof(Base)=12
{
public:
int a;
protected:
char b;
private:
float c;
};
class Derive:public Base//派生类sizeof(Derive)=24
{
public:
int d;
protected:
char e;
private:
float f;
};
★派生类继承除构造和析构外基类的所有成员和他们的作用域。
Protected和private的主要区别在继承,protected用于继承结构中。
Private只有自己和友元可见,派生类可继承但不可见,可通过基类提供的函数间接访问。
这里补充说一点:VS/VC下,*.c不允许定义空struct。C++中,sizeof(空class)=1,sizeof(空struct)=1
gcc下,C中sizeof(空struct)=0,C++中,sizeof(空class)=1,sizeof(空struct)=1
---------------------------------------------------------------------------------------------------------------------------------------------
派生类无法构造基类继承来的部分,只能构造自己的那部分
★最先构造成员对象(如果有) 然后构造基类 再构造派生类
对于基类和派生类名字相同的成员(方法):
重载 函数名同,参数列表不同,作用域同
隐藏 继承结构中,基类、派生类中有相同的名字
覆盖 继承结构中,基类有虚函数,且派生类有相同名,相同参数,返回值,则基类该函数被覆盖。
然后又是一个栗子:
class Base
{
public:
Base(int a):ma(a){cout<<"Base()"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
void show(){cout<<"lalala"<<endl;}//隐藏,可用作用域访问
void show(int m){cout<<ma<<endl;}//隐藏,可用作用域访问
void fun(){cout<<"???"<<endl;}//可被派生类对象调用
protected:
int ma;
};
class Derive:publicBase
{
public:
Derive(int a):mb(a),Base(a){}//基类在派生类成员初始化列表构造
~Derive(){}
void show(){cout<<"xixixi"<<endl;}
private:
int mb;
};
int main()
{
Derive d(2);
d.Base::show();
d.Base::show(2);
d.fun();
Base *p = &d;
p->show();//编译阶段就可确定show()来自哪个类,静态绑定(普通函数)
//call Base::show()
cout<<typeid(p).name()<<endl;//Base*
cout<<typeid(*p).name()<<endl;//Base
cout<<sizeof(Derive)<<endl;//8
}
class Base
{
public:
Base(int a):ma(a){cout<<"Base()"<<endl;}
~Base(){cout<<"~Base()"<<endl;}
virtual void show(){cout<<"lalala"<<endl;}//被覆盖
void show(int m){cout<<ma<<endl;}
protected:
int ma;
};
class Derive:public Base
{
public:
Derive(int a):mb(a),Base(a){}
~Derive(){}
void show(){cout<<"xixixi"<<endl;}//也成虚函数
private:
int mb;
};
int main(){
Derive d(2);
Base *p = &d;
p->show();
//mov ecx,dword ptr[pb] ecx放虚函数表的地址
//mov eax,dword ptr[ecx] eax放第一个虚函数的地址
//call eax //动态绑定,运行时才知道这个值(虚函数)
cout<<typeid(p).name()<<endl;//Base*
cout<<typeid(*p).name()<<endl;//Derive
cout<<sizeof(Derive)<<endl;//8+4=12,这个下面就说~~~~~
}
派生类中函数名相同,参数列表同的函数自动被处理成 虚函数
类中有虚函数的时候,在 编译阶段 会生成一个vftable(虚函数表,放各种虚函数的地址) 类的对象共享一张表
虚函数指针vfptr(指向虚函数表入口地址)占4字节
→所以当类中有虚函数,类对象大小要加4字节。
派生类继承基类的虚函数表,但是由于覆盖原理,虚函数里的函数地址会变成自己的函数(会变成虚函数了)。
→所以,基类、派生类都有自己的虚函数表。
------------------------------------------------------------------------------------------------------------
(๑¯ิε ¯ิ๑) over~栗子全都来源老师上课内容,运行结果懒得截图所以直接写旁边了