C++学习笔记27,虚函数作品

C++它指定虚函数的行为,但实现的作者编译器.

通常,编译器处理虚函数的方法是给每个对象加入一个隐藏成员.隐藏成员中保存了一个指向函数地址数组的指针.

这个数组称为虚函数表(virtual function table,vtbl).虚函数表中存储了为类对象进行声明的虚函数的地址.

比如:基类对象包括一个指针,该指针指向基类的虚函数表.

派生类对象包括一个指针,该指针指向一个独立的虚函数表.假设派生类提供了虚函数的新定义,虚函数表将保存新的函数地址.

假设派生类没有又一次定义虚函数,虚函数表将保存原版本号的地址.假设派生类定义了新的虚函数,则将该函数地址也加入到虚函数表中!

看以下的样例:

#include <iostream>
#include <string>
using namespace std;
class Animal{
protected:
	string name;
public:
	Animal(const string &s):name(s){
	}
	virtual ~Animal(){
	}
	//非虚函数
	void eat()const{
		cout<<"Animal eat!"<<endl;
	}
	//不被重写的虚函数
 	virtual void run()const{
		cout<<"Animal run!"<<endl;
	}

	//会被重写的虚函数
	virtual void speak()const{
		cout<<"I'm a Animal!"<<endl;
	}
};
class Dog:public Animal{
public:
	Dog(const string &s):Animal(s){
	}
	virtual ~Dog(){
	}
	//新定义的函数eat,将掩盖旧的版本号,非重写(重写是指重写virtual函数)
	void eat()const{
		cout<<"Dog eat!"<<endl;
	}
	//重写speak()
	virtual void speak()const override{
		cout<<"This's a Dog!"<<endl;
	}
	//新的虚函数
	virtual void fun1()const{
	}
};
int main(){
	Animal a("AnimalOne");
	Dog d1("DogOne");

	Animal *p1=&a;
	Animal *p2=&d1;
	p1->speak();
	p2->speak();
	p1->eat();
	p2->eat();	//call Animal::eat()
	p1->run();
	p2->run();	//call Animal::run()

	Animal &r1=a;
	Animal &r2=d1;
	r1.speak();
	r2.speak();
	r1.eat();
	r2.eat();
	r1.run();
	r2.run();

	return 0;

}

注意eat不是虚函数,不会保存在虚函数表中

//Animal虚函数表
地址:1000

Animal::run()        4000

Animal::speak()                  5000

Dog虚函数表  地址:2000

Dog::run()        4000(没有被重写,保存原地址)

Dog::speak()  
7000(重写了,保存新地址)

Dog::fun() 8000(新的虚函数,保存地址)

具体分析以下的代码

p1->speak();
//找到Animal中speak的地址,5000

p2->speak();
//找到Dog中speak的地址,7000,运行代码Dog::speak();

p1->run();
//同上

p2->run();
//

这样,对于虚函数表就有了一的初步认识!


版权声明:本文博客原创文章。博客,未经同意,不得转载。

时间: 2024-08-02 07:33:07

C++学习笔记27,虚函数作品的相关文章

C++学习笔记27,虚函数的工作原理

C++规定了虚函数的行为,但是将实现交给了编译器的作者. 通常,编译器处理虚函数的方法是给每一个对象添加一个隐藏成员.隐藏成员中保存了一个指向函数地址数组的指针. 这个数组称为虚函数表(virtual function table,vtbl).虚函数表中存储了为类对象进行声明的虚函数的地址. 例如:基类对象包含一个指针,该指针指向基类的虚函数表. 派生类对象包含一个指针,该指针指向一个独立的虚函数表.如果派生类提供了虚函数的新定义,虚函数表将保存新的函数地址. 如果派生类没有重新定义虚函数,虚函

C++学习笔记--从虚函数说开去

虚函数与纯虚函数: 虚函数:在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数,virtual  函数返回类型  函数名(参数表){函数体;} ,实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数.注意虚函数在基类中是有定义的,即便定义是空. 纯虚函数:在基类中是没有定义的,必须由派生类重定义实现,否则不能由对象进行调用. 看下面的例子: #include<iostream> using namespace std; class Cshape { p

C++ Primer Plus学习笔记之虚函数

C++ Primer Plus学习笔记之虚函数 C++语言的多态性有两种类型:静态多态性和动态多态性.函数重载和运算符重载就是静态多态性的具体表现,而动态多态性是指程序运行过程中才动态的确定操作所针对的对象,它是通过虚函数实现的: 1,虚函数的概念: 一个指向基类的指针可用来指向从基类派生的任何对象,这样就可以达到一个接口多个实现的访问了:虚函数是在基类中被冠以virtual的成员函数,它提供了一种接口界面.虚函数可以在一个或者多个派生类中被重新定义,但要求在派生类中从新定义时,虚函数的函数原型

学习笔记---C++虚函数,纯虚函数

1 .虚函数 假设people是man的父类,people类和man类都定义了实函数walk() people* p = new man(); p->walk(); 这里P执行的是people类的walk()函数.这和java语言不一样,java在这里执行的是man的walk()函数.那么C++如何实现子类的方法重写,并动态定位到子类方法? 这里必须使用virtual关键字 定义父类和子类的walk() virtual void walk(); 现在执行 p->walk();就是执行的子类的w

C++学习笔记11--纯虚函数和抽象类

纯虚函数:没必要或者不应该有函数体的虚函数,用"=0;"来取代函数体.有纯虚函数的类称为抽象类(缺少函数体),不允许直接用抽象类来创建对象.抽象类总数用来作为父类,由子类来实现(覆盖)那些纯虚函数,从而可以创建子类类型的对象.子类对象可以当成父类对象的引用,或者可以用父类指针指向子类对象. ×××××使用多态时必须通过父亲指针或者引用来访问子对象,而不能重建一个父类对象×××× #include<iostream> using namespace std; #include

学习笔记之gethostbyaddr函数

刚才学了gethostbyname函数,这个gethostbyaddr函数的作用是通过一个IPv4的地址来获取主机信息,并放在hostent结构体中. #include <netdb.h> struct hostent * gethostbyaddr(const char * addr, socklen_t len, int family);//返回:若成功则为非空指针,若出错则为NULL且设置h_errno //上面的const char * 是UNP中的写法,而我在linux 2.6中看到

Lua学习笔记(六):函数-续

Lua中的函数是带有词法定界(lexical scoping)的第一类值(first-class values).第一类值指:在Lua中函数和其他值(数值.字符串)一样,函数可以被存放在变量中,也可以存放在表中,可以作为函数的参数,还可以作为函数的返回值.词法定界指:嵌套的函数可以访问他外部函数中的变量.这一特性给Lua提供了强大的编程能力. Lua中关于函数稍微难以理解的是函数也可以没有名字,匿名的.当我们提到函数名(比如print),实际上是说一个指向函数的变量,像持有其他类型的变量一样:

十四、Android学习笔记_Android回调函数触发的几种方式 广播 静态对象

一.通过广播方式: 1.比如登录.假如下面这个方法是外界调用的,那么怎样在LoginActivity里面执行登录操作,成功之后在回调listener接口呢?如果是平常的类,可以通过构造函数将监听类对象传入即可.但是在Activity中不能传递监听对象,所以考虑使用广播来实现. public void login(final LoginOnClickListener listener) { Intent intent = new Intent(context, LoginActivity.clas

大龙的学习笔记之“虚方法,抽象方法,重写,抽象类,接口”

虚方法:可以重写,也可以不重写,英文名:virtual 抽象方法:必须重写,必须放在抽象类中,英文名:abstract 重写:可以重写三种方法:virtual,abstract,override,英文名:override 抽象类:可以有抽象方法,也可以有非抽象方法,英文名:abstract 接口:和抽象类相似,但是里面只有未实现的方法,英文名:interface 大龙的学习笔记之"虚方法,抽象方法,重写,抽象类,接口",布布扣,bubuko.com