C++中基类和派生类之间的转换实例

2023-11-10



本文实例讲解了C++中基类和派生类之间的转换。对于深入理解C++面向对象程序设计有一定的帮助作用。此处需要注意:本文实例讲解内容的前提是派生类继承基类的方式是公有继承,关键字public。具体分析如下:

以下程序为讲解示例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include<iostream>
using namespace std;
 
class A
{
public :
   A( int m1, int n1):m(m1), n(n1){}
   void display();
private :
   int m;
   int n;
};
 
void A::display()
{
   cout << "m = " << m << endl;
   cout << "n = " << n << endl;
}
 
class B : public A
{
public :
   B( int m1, int n1, int p1) :A(m1, n1), p(p1){}
   void display();
private :
   int p;
};
 
void B::display()
{
   A::display();
   cout << "p = " << p << endl;
}
 
void print1(A& a)
{
   a.display();
}
 
void print2(B& b)
{
   b.display();
}
 
void print3(A a)
{
   a.display();
}
 
void print4(B b)
{
   b.display();
}
 
int main()
{
   A a(3, 4);
//  a.display();
   B b(10, 20, 30);
//  b.display();
 
   A * pa;
   B * pb;
   pa = &a;
//  pa->display();
   pb = &b;
//  pb->display();
 
//  pa = &b;
//  pa->display();
 
//  pb = &a;       //错误。派生类指针不能指向基类对象。
 
//  print1(b);
//  print2(a);      //错误。不能用基类对象给派生类引用赋值。
//  print3(b);
//  print4(a);      //错误。不能用基类对象给派生类对象赋值。
 
//  pb = pa;       //不能用基类指针给派生类指针赋值。
 
   pb = (B*)pa;     //可以强制转换,但是非常不安全。
   pb->display();    //出现安全问题,p无法访问,因为a中没有p成员
   system ( "pause" );
   return 0;
}

切记:派生类对象是基类对象,派生类中包含有基类的成员。基类对象不是派生类对象,它不能包含派生类型的成员。

一、派生类到基类的转化

1.派生类对象地址赋值给基类指针

main函数中执行以下代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
A a(3, 4);
//  a.display();
   B b(10, 20, 30);
//  b.display();
 
   A * pa;
//  B * pb;
//  pa = &a;
//  pa->display();
//  pb = &b;
//  pb->display();
 
   pa = &b;
   pa->display();     //会输出 10 20

pa为基类指针,指向派生类对象是合法的,因为派生类对象也是基类对象。语句会输出派生类对象中基类部分。

注意:这里并不会调用派生类的display函数,调用的是基类的display函数,因为指针pa是基类指针,编译器在编译阶段只知道pa的类型。如果要实现调用派生类的display函数,需要用到虚函数实现多态性。之后的文章会讲到。

进一步解释一下编译时和运行时的区别。

编译时编译器能知道pa的类型为A *,但是不知道它指向了哪个对象,假如有以下语句

?
1
2
3
4
5
6
7
8
9
A a(3, 4);
B b(10, 20, 30);
A* pa;
int number;
cin >> number;
if (number >= 0)
   pa = &a;
else
   pa = &b;

pa指向的对象类型依赖于输入,运行时才输入,所以编译器是没有办法知道pa指向哪个类型的。

2.派生类对象赋值给基类引用

引用跟指针基本没有区别,引用本质上是指针,是个指针常量,具体可以参照我的另一篇C++中的引用和指针的联系和区别

main函数中执行以下代码

?
1
2
3
A a(3, 4);
B b(10, 20, 30);
print1(b);      //会输出 10 20

形参为基类引用,实参为派生类对象,派生类对象也是基类对象,可以赋值给基类引用。输出派生类中基类部分。

注意:此时对象本身并未复制,b仍然是派生类对象,前面说过了引用就是一个指针

3.派生类对象赋值给基类对象。

?
1
2
3
A a(3, 4);
B b(10, 20, 30);
print3(b);

派生类对象基类部分被复制给形参。

注意:实际上没有从派生类对象到基类对象的直接转换。对基类对象的赋值或初始化,实际上在调用函数,初始化时调用构造函数,赋值时调用赋值操作符。

二、基类到派生类的转化

切记:这种转换有可能引发严重的安全问题,编写代码时不要使用。没有基类到派生类的自动转换,原因在于基类对象只能是基类对象,不能包含派生类型的成员

如果允许用基类对象给派生类对象赋值,那么就可以试图使用该派生类对象访问不存在的成员。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
A a(3, 4);
B b(10, 20, 30);
A * pa;
B * pb;
//  print2(a);      //错误。不能用基类对象给派生类引用赋值。
//  print4(a);      //错误。不能用基类对象给派生类对象赋值。
//  pb = &a;       //错误。派生类指针不能指向基类对象。
 
pa = &a;
pb = &b;
 
//pb = pa;           //错误。不能用基类指针给派生类指针赋值。
 
pb = (B*)pa;     //可以强制转换,但是非常不安全。
pb->display();    //出现安全问题,p无法访问,因为a中没有p成员

注意到我们使用强制转换时,当派生类添加了基类中不存在的成员时,会出现安全问题。

pb->display();会调用派生类的display函数,但是它指向的内存是基类对象a的内存,p不存在。会出现严重后果。


转载于http://www.jb51.net/article/54222.htm

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++中基类和派生类之间的转换实例 的相关文章

  • 从 Makefile 中的 C++FLAGS 中删除一个标志?

    我有一个 Makefile 其中包含另一个设置了很多默认值的 makefile 我无法编辑包含的 makefile 并且我想更改 makefile 中 C FLAGS 的值 即使它是在包含的 makefile 中设置的 具体来说 每当 de
  • 函数“sum”的隐式声明在 C99 中无效

    我一直在寻找解决方案 但没有找到任何有帮助的东西 我收到以下错误 Implicit declaration of function sum is invalid in C99 Implicit declaration of function
  • 如何从对Web服务发出的请求中获取客户端IP地址

    我的 IIS 中托管有一个 Web 服务 当客户端直接使用我的服务时 我需要找出客户端 IP 地址 like http MyIpAddress MyApplication MyWebServiceClass asmx http MyIpAd
  • 为什么迭代器类型推导失败? [复制]

    这个问题在这里已经有答案了 为什么这在 C 中不起作用 为什么我不能限制foo的参数为std vector
  • 如何准备sql语句并绑定参数?

    不幸的是 文档 http www sqlite org完全缺乏示例 这真的很奇怪 就好像它假设所有读者都是优秀的程序员一样 然而 我对C 并且无法真正从文档中弄清楚如何真正准备和执行语句 我喜欢它的实施方式PDO for PHP 通常 我只
  • 如何进行Visual Studio格式字典初始化?

    所有 Visual Studio 也包括 2012 不格式化以下内容 messageProcessor new Dictionary
  • 仅针对某些异常类型中断

    我知道异常处理是一件非常重要的事情 我们在所有项目中都在这样做 主要原因是记录客户发生的错误 这工作正常 根本不是问题 但是 当我仍在使用 Visual Studio 编码和运行应用程序时 我根本不需要任何异常处理 我希望调试器正好停在应用
  • 使用正则表达式解析日志文件

    我目前正在为我们的内部日志文件 由 log4php log4net 和 log4j 生成 开发一个解析器 到目前为止 我有一个很好的正则表达式来解析日志 除了一个烦人的一点 一些日志消息跨越多行 我无法正确匹配 我现在的正则表达式是这样的
  • 如何从命名空间内重载运算符<<

    这是我能想到的最小的包含示例 首先是类的标题 每当使用 pragma once ifndef EURO H define EURO H include
  • WPF ComboBox 中具有本地化名称的枚举

    我有一个列出枚举的组合框 enum StatusEnum Open 1 Closed 2 InProgress 3
  • C# 中不区分大小写的替换不使用正则表达式?

    有没有一种方法可以在不使用 C 中的正则表达式的情况下对字符串进行不区分大小写的替换 像这样的东西 string x Hello x x Replace hello hello world 你可以尝试类似的东西 string str Hel
  • C# SignalR 异常 - 连接在收到调用结果之前开始重新连接

    我正在开发 2 个应用程序 第一个是 C 控制台应用程序 另一个是 Asp net Web 应用程序 我正在使用 SignalR 连接两者 这是我的 C 控制台应用程序 客户端 public class RoboHub public sta
  • C# 从今天起 30 天

    我需要我的应用程序从今天起 30 天后过期 我会将当前日期存储在应用程序配置中 如何检查应用程序是否已过期 我不介意用户是否将时钟调回来并且应用程序可以正常工作 用户太愚蠢而不会这样做 if appmode Trial string dat
  • 为什么将未使用的返回值转换为 void?

    int fn void whatever void fn 是否有任何理由将未使用的返回值强制转换为 void 或者我认为这完全是浪费时间 David s answer https stackoverflow com questions 68
  • 如何在RcppParallel中调用用户定义的函数?

    受到文章的启发http gallery rcpp org articles parallel distance matrix http gallery rcpp org articles parallel distance matrix 我
  • 如何使用 MongoDB 实现 ASP.NET Core 3.1 Identity?

    是一个 API 用于简化后端和逻辑代码来管理用户 密码 个人资料数据 角色 声明 令牌 电子邮件确认等 对于 Visual Studio 来说 支撑脚手架 https learn microsoft com en us aspnet cor
  • 智能感知不显示评论

    如果我在 Visual Studio 2010 中输入类似的内容数据集1 我得到所有可用方法和属性的列表 智能感知 这很好用 但是 如果我在此列表中选择一个方法或属性 我不会得到 if 的描述 例如 如果我有类似的东西 public cla
  • 为什么 getch 不可移植?

    是什么使得 getch 本质上无法作为标准 C 函数包含在内 对于控制台界面来说 它是如此直观和优雅 如果没有它 要求输入单个字符总是会产生误导 因为用户可以输入多个键 更糟糕的是 您经常需要确保在读取控制台输入后清除标准输入 这甚至不是作
  • OpenCV 仅围绕大轮廓绘制矩形?

    第一次发帖 希望我以正确的方式放置代码 我正在尝试检测和计算视频中的车辆 因此 如果您查看下面的代码 我会在阈值处理和膨胀后找到图像的轮廓 然后我使用 drawContours 和矩形在检测到的轮廓周围绘制一个框 我试图在 drawCont
  • 从 git 签出后 nuget dll 丢失

    I have a C solution containing different projects On those projects I have some normal nuget packages like Newtonsoft Js

随机推荐

  • 什么是吉布斯采样(Gibbs Sampling)

    目录 1 蒙特卡洛方法 1 1 蒙特卡洛方法的作用 1 2 非均匀分布采样 1 3 分布p x 不好采样怎么办 2 什么是吉布斯采样 2 1 马尔可夫链 2 1 1 什么是马尔可夫链呢 2 1 2 为什么我们要引入马尔可夫链 2 1 3 对
  • 快速学会git版本管理——创建分支和合并分支

    首先创建分支 git创建分支只需要使用switch 命令 git switch c 分支名 创建分支并切换到该分支 大家看后面的括号里已经变成了dev 说明我们切换成功了 然后想要合并分支就在 创建的分支中 进行提交修改的内容 还是通过 a
  • 5G QoS控制原理专题详解-QoS控制原理(2)

    相关文章会在公众号同步更新 最近工作忙 更新完公众号后 经常容易忘记再CSDN上再发 公众号上的文章更新的能快一些 各位同学有兴趣可以关注一下 公众号 5G通信大家学 持续更新的相关5G内容都是直接根据3GPP整理 保证更新内容的准确性 避
  • OOM(内存溢出)造成原因及解决方案

    一 概念 内存溢出 Out Of Memory 简称OOM 是指应用系统中存在无法回收的内存或使用的内存过多 最终使得程序运行要用到的内存大于能提供的最大内存 二 造成原因 2 1 内存泄漏 由于长期保持某些资源的引用 垃圾回收器无法回收它
  • first season seventh episode,The entire city is blacked out!(全城大停电,Chandler有好事???)

    Scene Central Perk Rachel is introducing Phoebe who is playing her guitar for the crowd Rachel Everybody Shh shhh Uhhh C
  • 【Java项目】多文件传输

    1 前言 为了实现一个C S框架应用 客户端向服务器请求资源 采用传统的BIO模式传输 问题 但当客户端数量增加 传输效率下降 尤其是多个客户端请求1G文件时 传输大概有十多分钟 问题分析 客户端所需要的资源都是通过服务器单独发送 当请求增
  • Angular6项目构建

    Angular6项目构建 安装Nodejs长期支持版本 LTS 设置npm淘宝代理 npm config set registry https registry npm taobao org npm install g angular cl
  • linux 使用chomd给文件授权 报错 -bash: chomd: 未找到命令

    1 简介 chmod是一个Linux Unix命令 用于更改文件或目录的权限 2 解决方案 以下是一些常见的解决方案 输入命令时检查有无拼写错误 确认您是否具有执行该命令所需的权限 检查您的系统是否已安装此命令 您可以尝试使用whereis
  • 忘记iPhone锁屏密码?三种方法帮你顺利解决!

    不论是苹果手机用户还是安卓手机用户 如果开机的锁屏密码忘记的话 应该是比较麻烦的一件事情 iPhone用户如果连续尝试6次密码都不对的话 iPhone将会自动锁死 也就变成了我们常说的 砖机 不过在iPhone锁死之前 我们还有三种方法可以
  • 在WindowsXP系统下搭建PPPoE服务器总结

    对与路由器的测试中遇到一个问题就是PPPoE的测试 具体如下 一 组网图如下 二 要确保WindowsXP系统的服务中Workstation Telephony Remote Access Connection Manager Routin
  • 已获万赞,最新Android通用流行框架大全

    前言 2021全年从开头到结尾似乎就没多少好消息 这里我说的是整个互联网行业 并没有单单挑出某个公司或者某个细分领域 而对于广大Android开发者来说 找工作似乎也变得越来越难了 2021年1月 我在51job搜索了一下北京地区的Andr
  • 基于STM32 的IIC 模拟主机编写

    最近在学习STM32 的IIC IO 模拟主机方式 好像失败了 include myiic h include delay h MCU VERSION DATA 作者 other Function IIC
  • 吴恩达深度学习笔记五:卷积神经网络 人脸识别和风格迁移部分

    1 人脸识别 人脸验证 Face Verification 输入图片和模板图片是否为同一人 一对一问题 人脸识别 Face Recognition 输入图片 检测是否为多个模板图片中的一个 一对多问题 一般来说 人脸验证由于范围较小难度较小
  • MyBatis实现乐观锁和悲观锁

    使用mysql做数据库 mybatis做orm的系统中 mybatis的乐观锁和悲观锁实际上就是mysql的乐观锁和悲观锁 实例中使用springboot整合mybatis 一并记录了 添加依赖
  • 【数据压缩】LZW编解码原理及算法实现

    一 LZW简介 LZW压缩 LZW compression 是一种由Abraham Lempel Jacob Ziv和Terry Welch发明的基于表查寻算法把文件压缩成小文件的无损压缩方法 LZW算法又叫 串表压缩算法 就是通过建立一个
  • 计算机毕业论文选题 - 毕设选题推荐

    文章目录 0 前言 1 java web 管理系统 毕设选题 2 java web 平台 业务系统 毕设选题 3 游戏设计 动画设计类 毕设选题 适合数媒的同学 4 算法开发 5 数据挖掘 毕设选题 6 大数据处理 云计算 区块链 毕设选题
  • npm 常用的命令

    目录 npm是什么 npm install 安装模块 npm uninstall 卸载模块 npm update 更新模块 npm outdated 检测模块是否过时 npm ls 查看安装的模块 npm init 初始化package j
  • Ubuntu +ros 的node的详解

    1 rosrun turtlesim turtlesim node 启用一个新的节点 2 rosnode list 就会发现一个新的节点 3 rosnode info turtlesim 查看节点的相关信息 4 就会看到发布者 以及相应的主
  • 原生js本地存储?看这一篇就够了!!!

    JS cookie 1 概述 cookie也叫HTTP Cookie 最初是客户端与服务器端进行会话 Session 使用的 如果没写expires 那么下次打开网页 cookie就会消失 这个就是会话机制 2 格式 name value
  • C++中基类和派生类之间的转换实例

    本文实例讲解了C 中基类和派生类之间的转换 对于深入理解C 面向对象程序设计有一定的帮助作用 此处需要注意 本文实例讲解内容的前提是派生类继承基类的方式是公有继承 关键字public 具体分析如下 以下程序为讲解示例 1 2 3 4 5 6