(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. python3基础: 元组tuple、 列表list、 字典dict、集合set。 迭代器、生成器

    一.元组: tuple Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组中的元素值是不允许删除的,但我们可以使用del语句来删除整个元组 tup2 = (111, 22, 33, ...

  2. 63.(原65)纯 CSS 创作一个摇摇晃晃的 loader

    原文地址:https://segmentfault.com/a/1190000015424389 修改后地址:https://scrimba.com/c/cqKv4VCR HTML code: < ...

  3. sass的基本使用

    使用sass的前提是安装Ruby,如果是Mac系统,那么免去安装,Windows系统需要自行安装https://www.sass.hk/install/.当安装好以后,直接执行安装sass命令:gem ...

  4. xadmin设置

    1.xadmin配置 INSTALLED_APPS = ( ... 'xadmin' , 'crispy_forms' , 'reversion' , ... ) 2.注册类 import xadmi ...

  5. Ubuntu 装nexus

    装nexus前提是装好JDK和maven 先下载 wget http://download.sonatype.com/nexus/oss/nexus-2.12.0-01-bundle.tar.gz 再 ...

  6. java学习笔记(十):scanner输入

    可以通过 Scanner 类来获取用户的输入. 通过next()类和nextLine()类来获取字符串. 通过 Scanner 类的 next() 类来获取输入的字符串. import java.ut ...

  7. linux下的音量控制器alsamixer 桌面v7

    转载 http://blog.sina.com.cn/s/blog_0ca103850102vpml.html 耳机 插后边 line out 耳机插前边 模拟耳机 声卡自带工具 linux下的音量控 ...

  8. ES6 Number

    1. 新增Number.EPSILON(误差检查函数)

  9. eclipse中启动项目报内存溢出问题通过修改配置解决

     标注:添加下面的参数还是挺管用的,本人亲测可试,同时启用两个项目,总是报堆内存不足,加了下面的参数后变可以同时正常运行了. 错误如下: Error occurred during initializ ...

  10. makefile中一些编译器选项

    Libraries Static Libraries a collection of ordinary object files (目标文件的集合) loaded at program link ti ...