c++父类指针强制转为子类指针后的测试(帮助理解指针访问成员的本质)(反多态)
看下面例子:
#include "stdafx.h"
#include <iostream>
class A { //父类
public:
void f() //普通函数
{
std::cout<<"A"<<std::endl;
}
void virtual vf() //虚函数
{
std::cout<<"virtual-A"<<std::endl; }
};
class B : public A //子类
{
public:
void f()
{
std::cout<<"B"<<std::endl;
}
void virtual vf()
{
std::cout<<"virtual-B"<<std::endl;
}
int m; //B类的成员变量
B() //在B类的构造中给成员变量赋值
{
this->m=20;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A *pa = new A(); //只实例化一个父类的对象,但下面要当作子类用
B *pb = (B *)pa; //用强制类型转换,把父类指针转化为子类指针,用这个子类指针访问子类的成员
pb->f(); //覆盖时,调用的是子类的函数
pb->vf(); //虚函数时,调用的是父类的函数,是因为虚函数表记录的是父类的方法,没有显示new一个子类,所以不会改虚函数表的内容
std::cout<<pb->m<<std::endl; //结果输出的是乱码,不是20
//原因,要输出子类的成员变量m,但实际上pb指向的内存空间只有父类大小,所以访问的m实际上是超出了实例化的对象的范围 return 0;
}
运行结果:

总结:其实可以这样理解,根据某个类型的指针访问某个成员时,编译器会根据类型的定义, 查找这个成员(对编译器来讲成员名只是个标记)所在偏移量,用这个偏移量获取成员。 比如上面用指针pb访问成员变量m时,m对于pb来说只是个标记,说明要从pb开始偏移多少个字节才能访问到m。
上面的例子我称为“反多态”,因为,通过一个多态的指针(多态时是父类型的指针,上面的例子是子类型的指针)访问普通成员函数时访问的是子类的函数(刚好和多态相反),通过子类的指针访问虚函数时访问的是父类的函数(也刚好和多态相反)。
c++父类指针强制转为子类指针后的测试(帮助理解指针访问成员的本质)(反多态)的更多相关文章
- 传入的结构体指针强制转为实例化结构体*v
struct val *v = (struct val *)arg;//传入的结构体指针强制转为实例化结构体*v struct val{ int num1; int num2; }; void *te ...
- c# 父类的引用指向子类的实例
在C#中关于父类对子类的引用大概有这么几种: 父类是接口,普通类,抽象类 public interface A { void a(); } public class B { public void b ...
- C++虚函数表解析(图文并茂,非常清楚)( 任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法)good
C++中的虚函数的作用主要是实现了多态的机制.关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数.这种技术可以让父类的指针有“多种形态”,这是一种泛型技术 ...
- C++析构函数的自动调用(析构函数必须是虚拟的,这样删除父类指针指向的子类对象,才能同时调用两者的析构函数,否则就没有机会调用子类析构函数)
class A {public: A() { printf("A \n"); } ~A() { printf(" ~A \n"); } // 这里不管写不写vi ...
- Java中父类强制转换为子类的可能
之前徒弟问了一个问题, 在Java中, 父类对象到底能不能转换成对应的子类对象? 到底能不能, 今天就来说说这个问题, 先看下面一段代码: package cn.com.hanbinit.test; ...
- c++ 动态判断基类指针指向的子类类型(typeid)
我们在程序中定义了一个基类,该基类有n个子类,为了方便,我们经常定义一个基类的指针数组,数组中的每一项指向都指向一个子类,那么在程序中我们如何判断这些基类指针是指向哪个子类呢? 本文提供了两种方法 ( ...
- Java父类强制转换子类原则
最近,微信群友在讨论子类父类的转换问题,其实不难,给大家用实例来说明一下就很明了了. 我们知道Java中子类转换成父类是没有任何问题的,那父类可以转换成子类吗? 来看下面这段程序: public cl ...
- Qt之美(一):d指针/p指针详解(解释二进制兼容,以及没有D指针就会崩溃的例子。有了D指针,所使用的对象大小永远不会改变,它就是该指针的大小。这个指针就被称作D指针)good
Translated by mznewfacer 2011.11.16 首先,看了Xizhi Zhu 的这篇Qt之美(一):D指针/私有实现,对于很多批评不美的同路人,暂且不去评论,只是想支持 ...
- 你好,C++(40)7.1 一切指针都是纸老虎:彻底理解指针
第7章 C++世界的奇人异事 在武侠小说中,初入武林的毛头小子总是要遇到几位奇人,发生几件异事,经过高人的指点,经历一番磨炼,方能武功精进,从新手成长为高手.在C++世界,同样有诸多的奇人异事.在C+ ...
随机推荐
- CSS小结
一.1. css必须写在<head></head>里面的<style></style>里面 2. css 由选择器 + 规则组成, 规则由属性和值组成 ...
- HDFS使用0
创建上传文件的:
- Merge k Sorted Lists [LeetCode]
Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity. S ...
- Android MotionEvent事件响应机制
在android中,事件主要包括点击.长按.拖曳.滑动等操作,这些构成了Android的事件响应,总体来说,所有的事件都由如下三个部分作为基础构成: 按下(action_down),移动(action ...
- ABAP简单表维护的制作
为了知识的积累,特作了个简单的表维护. 因为自己之前做dynpro程序的时候建了一个Tree node的表,所以就不在此重复.(在表的交付和维护页签中标的属性要是‘允许标准表维护的’) 直接Alt+U ...
- settimeout如何调用方法的时候,传递参数
常见写法: setTimeout("loaded()", 200); 延迟加载loaded方法 如果要给loaded方法传递参数 setTimeout(function () { ...
- HTML中的一些常见的事件句柄
onclick 所有类似按钮的表单元素和标记<a>及<area>都支持该处理程序.当用户点击元素时会触发它.如果onclick处理程序返回false,则浏览器不执行任何与按钮或 ...
- SSH由WAS/Tomcat/Weblogic迁移到JBOSS
又是一个凌晨,又一次搞项目在新的中间件上的可部署性验证... 原来将项目部署到was7上,花了三个晚上到凌晨1点多的时间,总结出了只要将common-logging和wodenxx.jar两个jar包 ...
- easyui datagrid高度自适应问题
最近在使用datagrid的时候,发现在panel中嵌入一个datagrid时,当panel缩小时,datagrid下面会有一块空白,datagrid高度不能自适应,解决方法是在datagrid外面加 ...
- Asynchttpclient开源框架下载图片和文本,于Volley和Glide开源框架的区别。
AsyncHttpClient是一款比较流行的Android异步网路加载库,在github上的网址是:https://github.com/loopj/android-async-httpAsyncH ...