(1).对象类型:
          a.静态类型:对象声明时的类型,编译的时候确定
          b.动态类型:对象的类型是运行时才能确定的
class A
{};
class B:public A
{};
int main()
{
B* b;
A* a=b;//a的静态类型是A*,动态类型(运行时)类型是B*
return ;
}
(2).多态
          a.静态多态:函数重载、泛性编程   
int Add(int a,int b)
{
return a+b;
}
float Add(float a,float b)
{
return a+b;
}
int main()
{
cout<<Add(,)<<endl;;
cout<<Add(10.1f,20.2f)<<endl;;
return ;
}
在编译期间,编译器会根据函数实参的类型推断要调用那个函数
b.动态多态:虚函数
               1>.每个类都维护这一张虚表;调用虚函数查看对象是那个类,然后查表
               2>.基类可以使用为纯虚函数(virtual void fun()=0),基类就是抽象类要求子类实现

虚函数:
               含有虚函数或其父类含有虚函数的类,编译器都会为其添加一个虚函数表,vptr,
               虚基类表:虚继承产生虚基类表(vbptr),虚基表的内容与虚基表完全不同
               
**1**、单继承
           1)子类重写父类虚函数:
class A
{
public:
virtual void fun()
{
cout<<"A-fun()"<<endl;
}
A()
{}
~A()
{}
private:
int a1;
};
class B:public A
{
public:
void fun()
{
cout<<"B-fun()"<<endl;
}
B()
{}
~B()
{}
private:
int b1;
};
 

2)子类定义了新的虚函数:

class A
{
public:
virtual void fun()
{
cout<<"A-fun()"<<endl;
}
A()
{}
~A()
{}
private:
int a1;
};
class B:public A
{
public:
virtual void fun1()
{
cout<<"B-fun()"<<endl;
}
B()
{}
~B()
{}
private:
int b1;
};
 
**2**、多继承
          1)子类重写父类虚函数
class A
{
public:
virtual void Afun()
{}
private:
int a1;
};
class B
{
public:
virtual void Bfun()
{}
private:
int b1;
};
class C:public A,public B
{
public:
void Afun()
{}
void Bfun()
{}
private:
int c1;
};
int main()
{
A a;
B b;
C c;
cout<<sizeof(a)<<endl;
cout<<(int*)(&a)<<endl;
cout<<sizeof(b)<<endl;
cout<<(int*)(&b)<<endl;
cout<<sizeof(c)<<endl;
cout<<(int*)(&c)<<endl;
return ;
}

2)子类定义新的虚函数

class A
{
public:
virtual void Afun()
{}
private:
int a1;
};
class B
{
public:
virtual void Bfun()
{}
private:
int b1;
};
class C:public A,public B
{
public:
virtual void Cfun()
{}
private:
int c1;
};
int main()
{
A a;
B b;
C c;
cout<<sizeof(a)<<endl;
cout<<(int*)(&a)<<endl;
cout<<sizeof(b)<<endl;
cout<<(int*)(&b)<<endl;
cout<<sizeof(c)<<endl;
cout<<(int*)(&c)<<endl;
return ;
}

3) 菱形继承

class A
{
public:
void Afun()
{
cout<<"Afun()"<<endl;
}
A()
{}
~A()
{}
private:
int a1;
};
class B:public A
{
public:
void Bfun()
{
cout<<"Bfun()"<<endl;
}
B()
{}
~B()
{}
private:
int b1;
};
class C:public A
{
public:
void Cfun()
{
cout<<"Cfun()"<<endl;
}
private:
int c1;
};
class D:public B,public C
{
public:
void Dfun()
{
cout<<"D-fun()"<<endl;
}
private:
int d1;
};
**3**、虚继承(解决了菱形继承数据冗余和二义性的问题)(虚继承对应要有虚类指针)
          1)单一继承下的虚继承
class A
{
public:
virtual void Afun()
{}
private:
int a1;
};
class B:virtual public A
{
public:
void Afun()
{}
private:
int b1;
};
给B实例化一个对象,它的大小是16,是因为在虚继承过程中,会出现对应的虚类指针

***虚函数的主要作用是为了实现多态机制

class Base
{
virtual void print(void);
};
class Drive1:public Base
{
virtual void print(void);
};
class Drive2:public Base
{
virtual void print(void);
};
int main(int argc,char* argv[])
{
Base* ptr1=new Base;
Base* ptr2=new Drive1;
Base* ptr3=new Drive2;
ptr1->print();//调用base::print()
ptr2->print();//调用Drive1::print()
ptr3->print();//调用Drive2::print()
return ;
}这是一种运行期多态,父类指针唯有在程序运行时才能知道所致的真正类型是什么,这种运行期决议是通过虚函数表来实现的

***使用指针访问虚表

class Base
{
public:
Base(int i)
:base1(i)
{}
virtual void print(void)
{
cout<<"Base::print()"<<endl;
}
virtual void setl(void)
{
cout<<"Base::setl"<<endl;
}
virtual ~Base()
{}
private:
int base1;
};
int main(int argc,char* argv[])
{
Base b();
int* vptrAdree=(int*)(&b);
cout<<"虚函数指针(vptr)的地址是:\t"<<vptrAdree<<endl;
return ;
}
当一个类本身定义了虚函数或者其父类有虚函数时,为了支持多态机制,编译器为该类添加了一个虚函数指针(vptr),虚函数指针一般放在对象内存布局的第一个位置上,这是为了保证在多层继承或多重继承的情况下能以最高效率取到虚表
这个代码的mian()里我们取到了虚函数的地址(vptrAdree),虚函数指针指向虚函数表,虚函数表存的是一系列虚函数的地址,虚函数地址出现的顺序与类中虚函数声明的顺序一致
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

多态&虚函数的更多相关文章

  1. C++ (P199—P211)多态 虚函数 抽象类

    在介绍多态之前,先回忆:赋值兼容原则.虚基类.二义性.派生类如何给基类赋值等知识. 在赋值兼容原则中:父类对象的指针赋给基类的指针或者父类的对象赋给基类的引用,可以通过强转基类的指针或者引用变为父类的 ...

  2. 看懂下面C++代码才说你理解了C++多态虚函数!

    #include <iostream> using namespace std ; class Father { private :  virtual void Say()  //只有添加 ...

  3. OOP 多态/虚函数

    // main.cpp // OOP // 虚函数允许继承层次结构中绝大多数特定版本的成员函数被选择执行,虚函数使多态成为可能. // Created by mac on 2019/4/8. // C ...

  4. C++继承-重载-多态-虚函数

    C++ 继承 基类 & 派生类 一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数.定义一个派生类,我们使用一个类派生列表来指定基类.类派生列表以一个或多个基类命名,形式如下: ...

  5. c++学习之多态(虚函数和纯虚函数)

    c++是面向对象语言,面向对象有个重要特点,就是继承和多态.继承之前学过了,就是一种重用类的设计方式.原有的类叫父类,或者基类,继承父类的类叫子类.在设计模式中,我们总是要避免继承,推荐用组合.因为继 ...

  6. C++: 多态 虚函数

    一.多态: 1.多态是什么:具有不同功能的函数可以用同一个函数名 2.静态多态:程序编译时决定,通过函数重载实现. 3.动态多态:程序运行时决定,通过虚函数实现. 二.虚函数: 1.引入目的:可以通过 ...

  7. C++基础 (6) 第六天 继承 虚函数 虚继承 多态 虚函数

    继承是一种耦合度很强的关系 和父类代码很多都重复的 2 继承的概念 3 继承的概念和推演 语法: class 派生类:访问修饰符 基类 代码: … … 4 继承方式与访问控制权限 相对的说法: 爹派生 ...

  8. 【C++基础】 多态 虚函数

    多态:同样的消息被不同类型的对象接收时导致不同的行为.这里“消息”是对类的成员函数的调用,“行为”调用了不同的函数. 分类:①重载多态 ②包含多态……等 实现:编译时的多态  运行时的多态(动态绑定) ...

  9. C++ polymorphism Virtual Function 多态 虚函数

    Polymorphism in C++ https://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm https://github.com ...

随机推荐

  1. gentoo 图像方面的软件

    图像方面的软件一般包括:查看图像,屏幕截图,图像修改. 查看图像简单的可以安装 feh,但是 feh 一般作为墙纸来用.稍微好一些的是 gqview. 屏幕截图可以用 screengrab,使用的时候 ...

  2. CSS vertical-align属性详解

    . 首页 博客园 联系我 前言:关于vertical-align属性. 实践出真知. 垂直居中. 第二种用法. 留言评论 返回顶部 前言:关于vertical-align属性 vertical-ali ...

  3. 剑指offer例题——用两个栈实现队列

    题目:用两个栈来实现一个队列,完成队列的Push和Pop操作.队列中的元素为int类型. 首先是概念理解,栈和对列存取的区别 栈(stack)是一种后进先出(last in first out, LI ...

  4. linux显示历史命令history

    history history//显示历史命令

  5. 为datagrid、treegrid增加右键表头菜单,用于显示或隐藏列,注意:冻结列不在此菜单中

    var createGridHeaderContextMenu = function(e, field) { e.preventDefault(); var grid = $(this);/* gri ...

  6. 微探eventlet.monkey_patch

    e ventlet.monkey_patch在运行时动态修改已有的代码,而不需要修改原始代码 在eventlet.monkey_patch中支持以下几种python原生库修改 eventlet.mon ...

  7. day34 并发编程之生产者消费者模型 队列

    1.守护进程(了解) """ 守护进程 表示 一个进程b 守护另一个进程a 当被守护的进程a结束后 那么b也跟着结束了 就像 皇帝驾崩 妃子殉葬 应用场景 之所以开启子进 ...

  8. CentOS 性能监测命令

    1.实时监测命令(watch) -d 高亮显示变化 -n 间隔多久(s) 执行后面的command #每隔1秒显示空间使用情况并列出当前目录下的列表信息 EX:watch -d -n 1 'df -h ...

  9. C++中的覆盖与隐藏(详细讲解)

    C++类中覆盖与隐藏一直是一个容易理解出错的地方,接下来我就详细讲解一下区别在何处 覆盖指的是子类覆盖父类函数(被覆盖),特征是: 1.分别位于子类和父类中 2.函数名字与参数都相同 3.父类的函数是 ...

  10. stark组件开发之批量操作

    class UserInfoHandler(StartHandler): ....... # 批量操作功能的列表,添加则显示, 使用此功能.需要将StartHandler.display_checkb ...