(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. 表单:!!!常用JS: form 表单代码

    手机(文本框): <input type="text" name="" maxlength="11" placeholder=&quo ...

  2. 3. tomcat 内存设置

    -Xms512m -Xmx1024m -XX:PermSize=512M

  3. kaggle首秀之intel癌症预测(续篇)

    之前写了这篇文章.现在把他搬到知乎live上了.书非借不能读也,因此搞了点小费用,如果你觉得贵,加我微信我给你发红包返回给你. 最近的空余时间拿去搞kaggle了, 好久没更新文章了.今天写写kagg ...

  4. 20165304 2017-2018-2《Java程序设计》学习总结

    20165304 2017-2018-2<Java程序设计>学习总结 一.每周作业及实验报告链接汇总 1.我期望的师生关系 2.20165304学习基础和C语言基础调查 3.linux系统 ...

  5. CSS样式学习-3、轮廓、伪类/元素、display-flex布局

    一.轮廓 outline绘制于元素周围的一条线,位于边框边缘外围. 属性规定元素轮廓的样式.颜色.宽度. outline-width轮廓宽度,属性:thin细轮廓.medium中等(默认值).thic ...

  6. JDK Timer & TimerTask

    目录 Timer & TimerTask Binary Heap Insert DELETE MIN PERFORMANCE LifeCycle Constructor MainLoop sc ...

  7. [C语言]进阶|指针与字符串

    ------------------------------------------------------------------------------------ 回顾:[C语言]指针与字符串 ...

  8. javascript隐式原型

    上图是js原型关系图. javascript是一种基于对象的编程语言,但它与一般面向对象的编程语言不同,因为它没有class类的概念 什么是原型?? 我们每创建一个函数,它就会自带一个原型函数,这个原 ...

  9. EntityFrameworkCore DBFirst

    需要引用如下nuget包 Microsoft.EntityFrameworkCore Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityF ...

  10. cdnbest如何在站点里开启强制缓存

    在站点设置中如下图设置: 强制缓存有两种方式,一种是文件类型,一种是url方式