C++基本功和 Design Pattern系列(2)

C++ Design Pattern(设计模式) 非四人帮的,类似网友的学习笔记本,不过写的还不错。 立即下载
C++基本功和 Design Pattern系列(2) Type Cast, InterfaceInheritance VS Implementation Inheritance
====================================================================

又到周末了,Aear在此感谢大家坐这么近来听我说书。今天讲的是C++的类型转换(比较无聊的内容,但最好看看,因为可以帮助大家减少程序中的bug)。许多学过C的朋友一定还记得C语言中的类型转换,例如:

float FloatNum = 1.234;
int IntNum = (int)FloatNum;
// IntNum = 1

这是比较正常的类型转换,稍微危险一点的转换如下:

float FloatNum = 1.234;
float * pFloatPointer = &FloatNum;
int * pIntPointer = (int *)pFloatPointer;
// *pIntPointer 里边就是乱七八糟的东西了

C的类型转换虽然很方便,但是却带来了更多的问题。比如 C的类型转换可以允许你进行任意类型之间的转换。 非常随意的使用类型转换很容易造成程序逻辑的混乱,使人看不懂你写的代码,或者编译器不能正确识别你的转换的意图,所以做出错误的转换方式。其次,C类型的转换很难查错。特别是在大型的工程中,你想找出一个因为 (uint)转换成 int而产生益出的问题,可能需要查看上千行包含"(int)"的代码。为了避免诸如此类情况的发生 C++引入了4种类型转换的方式。请记住,C的类型转换只是为C语言设计的,并不适合C++。C++支持C的类型转换只不过是为了向下兼容的考虑。

让我们来看看C++的4种类型转换(关于这4种类型转换的详细说明,请参见<C++ Programming Language> 3rd Edition):

static_cast<>()
dynamic_cast<>()
const_cast<>()
reinterpret_cast<>()

我们一个一个来说
================== static_cast ==================
static_cast<>() 
static_cast可以用来进行相关类型之见的转换,比如double 转成 float, float转成 int 以及 有关联的pointer之间,有关联的 class pointer 之间的转换。

========比如========

float FloatNum = 1.234;
int IntNum = static_cast<int>(FloatNum);    // IntNum = 1;

========或者========

class BaseClass{
public:
    BaseClass();
    virtual ~BaseClass();
};

class DerivedClass : public BaseClass{
public:
    DerivedClass();
    ~DerivedClass();
    void DoSomething(void);
};

BaseClass * pBaseClass = new BaseClass();
// 没问题,不过call pDerviedCalss->DoSomething()很有可能会crash
DerivedClass * pDerivedClass = static_cast<DerivedClass *>pBaseClass;

DerivedClass * pDerivedClass = new DerivedClass();
// 没问题,很安全
BaseClass * pBaseClass = static_cast<BaseClass *>(pDerivedClass);

值得注意的是 static_cast是在程序编译的时候检查类型转换是否符合要求,并不在程序运行期间进行检查,因为没有runtime overhead, 对速度的影响比较小。所以在你对类型转换很有把握的时候,可以尽量的使用static_cast。另外 static_cast在转换指针的时候并不能保证转换前的指针地址和转换后的指针地址相同,特别是在多重继承的类结构中,指针地址经常会变化。

下面是一些通常比较危险的类型转换,

========包括========
unsigned 转 sign 比如 uint 转成 int
double 转 float
long 转 int (64位操作系统有危险,32位无)

这些转换都是值域大的转成值域小的数,或者无符号转成有符号。比如:

unsigned int k = 4294967290;
int m = static_cast<int>(k);

这里k已经超出了int的值域,所以 m的最后结果是 -6。所以在做以上的类型转换的时候,要特别的小心。


================== dynamic_cast ==================
dynamic_cast是用来对相关的class 指针之间进行的类型转换。由于dynamic_cast在运行过程中对转换进行安全性检查,所以在很大程度上影响程序的运行速度,并且在便宜的时候需要打开runtime type info 的开关 /GR,所以并不推荐使用。

如果要使用dynamic_cast那么要求转换的类至少需要含一个虚函数,并且只能对类的指针进行转换操作,指针不包括 void *。 例如:

class BaseClass{
public:
    BaseClass();
    virtual ~BaseClass();
    virtual void DoSomething(void);
};

class DerivedClass : public BaseClass{
public:
    DerivedClass();
    ~DerivedClass();
    void DoSomething(void);
};

DerivedClass * pDerivedClass = new DerivedClass();
// 没问题
BaseClass * pBaseClass = dynamic_cast<DerivedClass *>(pDerivedClass);

BaseClass * pBaseClass = new BaseCalss();
// 有问题,基类转成派生类,dynamic_cast会返回null 所以 pDerivedClass == NULL
DerivedClass * pDerivedCalss = dynamic_cast<DerivedClass *>(pBaseClass);

================== const_cast ==================
顾名思义,就是把const变量转换成 non-const变量,或者把volatile转成non-volatile。这是最不推荐使用的一种转换,只有在特殊的情况下才会使用。如果你需要大量的使用const_cast,那么只能说明程序中存在着设计缺陷。

const_cast的使用如下:
float FloatNum = 12;
const float * pConstFloatPointer = &FloatNum;
// ok 这么用没问题
float * pFloatPointer = const_cast<float *>(pConstFloatPointer);
// 编译错误,const_cast只能进行const和non-const之间的转换
int * pFloatPointer = const_cast<int *>(pConstFloatPointer);

================== reinterpret_cast ==================
reinterpret_cast是最危险的一种转换类型,它并不对数据进行任何实际的转换操作,而是直接把数据当作另一种类型来使用(跟内存拷贝的功能差不多)。比如:

class ClassX{...};
class ClassY{...};

ClassX * pClassX = new ClassX();
// 没问题,不过除非classX和classY都是结构相同的interface,否则并不安全,程序很容易crash
ClassY * pClassY = reinterpret_cast<ClassY *>(pClassX);

reinterpet_cast比较有用的地方就是函数指针的转换,比如把一个指针存到一个函数指针数组中:

      typedef void (*FuncPtr)();
      FuncPtr FuncPtrArray[10];
      int DoSomething() {...};
      // 这里使用reinterpret_cast
      FuncPtrArray[0] = reinterpret_cast<FuncPtr>(&DoSomething);

总的来说,尽可能的使用这4种转换来清晰的表达你转换的目的,尽量不要使用C风格的转换。

================== Design Pattern ==================
今天的Design Pattern讲讲另外两个概念: Interface Inheritance 和 Implementation Inheritance。

上次Aear已经介绍了Inheritance 和 Delegation,并且说如果能用Delegation的地方,就最好不要使用Inheritance。但是如果必须使用Inheritance怎么办?因此就出现了不同使用Inheritance(继承)的方式。第一种就是 Interface Inheritance。

简单的说,Interface Inheritance就定义一个abstract class (抽象类),把所有提供的类方法都在这个抽象类中定义成纯虚函数,然后在派生类中实现这些虚函数。对于这个abstract class,我们可以称它为: Interface。 (是不是有点象 COM?)。 比如在游戏中,所有的敌人都可以移动和攻击,但是不同的敌人类型,攻击和移动的具体方式都不一样。我们就可以用一个抽象类在表示所有的敌人,在派生类中具体实现不同移动和攻击方式。
下面让我们来看看代码:

class Enemy{
public:
    virtual void Move(void) = 0;
    virtual void Attack(void) = 0;
};

// 人类敌人
class HumanEnemy : public Enemy{
public:
    void Move(void) {...}; // 用2条腿走路
    void Attack(void) {...}; // 用拳头或武器攻击
};

// 怪物敌人
class MonsterEnemy : public Enemy{
public:
    void Move(void) {...}; // 用4跳腿走路
    void Attack(void) {...}; // 用牙齿和爪子攻击
};

在运行AI的时候我们不需要具体判断对方是人类还是敌人,直接调用 move和attack就行了,代码如下:

void CalculateAction( Enemy * pEnemy)
{
    pEnemy->Move();
    pEnemy->Attack();
}

main()
{
   ....
   HumanEnemy * pHumanEnemy = new HumanEnemy();
   MonsterEnemy * pMonsterEnemy = new MonsterEnemy();
   CalculateAction(static_cast<Enemy *>pHumanEnemy);
   CalculateAction(static_cast<Enemy *>pMonsterEnemy);
   ....
}

=========== 小分割线 ===========

关于implementation inheritance,就是Aear在上一章里举的关于CBitmap和CTexture的例子。其中CBitmap只基类,提供了 GetBitmapHeight()方法。 CTexture是CBitmap的派生类,提供了GetTextureHeight()的方法。这种结构很容易使人产生程序逻辑结构的混乱,并不推荐使用。Aear的个人观点是:
    能使用 Delegation就用
    不能用Delegation就用 Interface Inheritance
    用不了Interface Inheritance就重新设计你的类结构,使之能使用前两种方式
    如果重新设计系统或者使用Interface Inheritance开销太大,再用Implementation Inheritance。

其实所有的Implementation Inheritance都可以通过Interface Inheritance来实现,具体来说,就是定义一个abstract class基类,在此基础上,定义派生类的abstract class (派生类也是interface),如此定义下去,直到所有需要实现的类都拥有自己的interface class为止。

好了就说这么多了,大家有空去我的blog坐坐Aear's Blog,下次见!


指纹浏览器指纹工厂(下):基于真实设备数据特征的马尔可夫链生成与校验 本文揭示了静态指纹生成算法在高级风控时序追踪下的致命缺陷,指出违背设备演进马尔可夫性质(如无状态跳跃、因果断裂)是导致指纹存活率骤降的核心原因。通过分析风控系统的时序状态机与多维特征验证机制,提出基于隐马尔可夫模型(HMM)的动态指纹架构:以真实设备的状态转移链为蓝本,构建异步演进的“数字基因熔炉”,通过非均匀时间步长、突发事件响应及微观因果绑定,模拟软硬件独立更新的物理法则。最终实现指纹在时间维度与微观特征上的自洽,规避风控的时序陷阱。 阅读详情

相关推荐

Qt 6.5实战:用QMediaPlayer搞定RTSP监控流播放(附LAV Filters解码器避坑指南)

本文详细介绍了如何在Qt 6.5中使用QMediaPlayer实现低延迟RTSP监控流播放,并提供了LAV Filters解码器的配置避坑指南。通过优化缓冲策略和硬件加速设置,显著提升视频流的播放性能和稳定性,适用于工业视觉检测和安防监控等实时场景。

weixin_33712987的博客 400

继承(Inheritance)和实现(Implementation)的区别、抽象类

继承强调类之间的“是一个”关系,通过继承父类的属性和方法实现代码复用,而实现则强调类的行为,通过实现接口定义的抽象方法来实现多种行为。

m0_62257437的博客 994

SystemVue 链路预算、仿真分析步骤

使用SystemVue进行链路预算、频谱分析等,相对ADS更全面。

BeCourageable的博客 3836

设计模式:Interface Inheritance (接口继承)和 Implementation Inheritance(实现继承)

设计模式:Interface Inheritance (接口继承)和 Implementation Inheritance(实现继承) 先阅读《具体类、抽象类、接口》:http://blog.youkuaiyun.com/iw1210/article/details/33727491 纯虚函数(pure virtual):派生类继承这个函数,并实现该函数。 虚函数(impure virtual):派生类

iw1210的专栏 2541

OpenWRT软件源更换保姆级教程:从国内镜像到官方源一键切换(含常见报错解决)

本文提供OpenWRT软件源更换的详细教程,涵盖从国内镜像源到官方源的切换方法,并深度解析常见报错解决方案。针对国内网络环境,指导用户如何精准定位系统信息、备份配置、选择并配置清华等国内镜像源,以及处理签名验证失败、依赖缺失、404错误等典型问题,旨在提升软件包管理效率与稳定性。

weixin_29229261的博客 1941

报错:subprocess.CalledProcessError: Command ‘[‘where‘, ‘cl‘]‘ returned non-zero exit status 1.

右键此电脑--属性--高级系统设置--环境变量--系统变量--找到Path。Enterprise是企业版,如果你是社区版就找Community。2.安装的时候,c++桌面那个需要勾选。

2301_77554343的博客 1507

C++-----reinterpret_cast

首先从英文字面的意思理解,interpret是“解释,诠释”的意思,加上前缀“re”,就是“重新诠释”的意思;cast在这里可以翻译成“转型”(在侯捷大大翻译的《深度探索C++对象模型》、《Effective C++(第三版)》中,cast都被翻译成了转型),这样整个词顺下来就是“重新诠释的转型”。我们知道变量在内存中是以“…0101…”二进制格式存储的,一个int型变量一般占用32个位(bit),参考下面的代码

weixin_45459266的博客 3975

手把手教你用DLP4500投影仪玩转结构光3D扫描(附固件烧录与序列设置避坑指南)

本文详细解析了如何使用DLP4500投影仪搭建结构光3D扫描系统,涵盖硬件组装、固件烧录、图案生成与优化等全流程。重点解决了固件烧录失败、图像格式错误等常见问题,并提供了实用的避坑指南和进阶技巧,帮助读者快速掌握DLP4500在3D扫描中的应用。

weixin_42662293的博客 301

C++基本功和 Design Pattern系列 Type Cast, Interface Inheritance VS Implementation Inheritance

许多学过C的朋友一定还记得C语言中的类型转换,例如:float FloatNum = 1.234;int IntNum = (int)FloatNum;// IntNum = 1这是比较正常的类型转换,稍微危险一点的转换如下:float FloatNum = 1.234;float * pFloatPointer = &FloatNum;int * pIntPointer = (int

杨德龙的专栏 1403

OBC_开环扫频波特图拟合操作流程(结合 Simulink)

摘要: 本文详细介绍了基于Simulink的开环扫频波特图测试与拟合流程,适用于电源/控制系统(如LLC/PFC)的小信号分析。主要内容包括:1)前期准备(测试点选择、信号范围设定);2)Simulink建模方法(信号注入、数据记录);3)两种扫频方式(逐频正弦/Chirp扫频)的实现;4)MATLAB数据处理(FFT分析、传递函数拟合);5)线性分析工具使用技巧。重点强调了激励信号幅值控制、稳态数据采集及模型验证方法,并提供完整MATLAB脚本示例。该流程可有效获取系统频域特性,为控制器设计提供可靠依据。

Sumerking的博客 234

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

100天精通Python(爬虫篇)——第122天:基于selenium接管已启动的浏览器(反反爬策略)

努力让自己发光,对的人才能迎着光而来 13万+

《Effective Java》笔记系列 复合优于继承(实现继承:implementation inheritance)

什么情况下继承是安全的: 1、子类和超类在同一个包中 2、对于专门为了继承而蛇姐,并且具有很好的文档说明的类 继承也是非常安全的。 对于普通的具体类跨包继承是非常危险的。 继承打破了封装性,子类依赖于超类的实现细节,当超累发生变化,子类可能会遭到破坏 使用复合:在新的类中添加一个私有域,引用现有类的一个实例,用转发的方式复用现有类中对应的方法。 只有当确定A和B之前是is-a时才应该使用继承 如果...

mysql数据库 innodb存储引擎怎么创建好索引 286

《Claude Code 实战》第 1 章:开启智能编程新纪元——初识 Claude Code

简单来说,Claude Code 是 Anthropic 公司推出的一款基于 Claude 3.7 Sonnet 等大语言模型的强大编程工具。但与传统的 ChatGPT 或普通的聊天机器人不同,Claude Code 具备了"动手"的能力。它不仅会"说",更会"做"。想象一下,你不再需要描述复杂的命令行参数,也不需要为了修改一个配置文件而频繁切换编辑器。Claude Code 可以直接读取你项目中的文件、理解复杂的代码库结构、执行终端命令,并直接为你生成或修改代码。

AI天才研究院 245

C++基本功和 Design Pattern系列(2) Type Cast, Interface Inheritance VS Implementation Inheritance

====================================================== 原创就是麻烦呀,最怕误人子弟....大家请把我的文章当参考,详细内容   还请参照 权威书籍 如果文中有错误和遗 漏,请指出,Aear会尽力更正, 谢谢!====================================================== 又到周末了,Aea

蚊子的Home-游戏开发 469

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++基本功和 Design Pattern系列(1) - Inheritance VS Delegation

 ====================================================== 大家请把我的文章当参考,详细内容  还请参照 权威书籍  如果文中有错误和遗漏, 请指出,Aear会尽力更正, 谢谢!====================================================== 首先恭喜C++版开张,这样Aear又多了一个可以发表

蚊子的Home-游戏开发 767

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

C++基本功和 Design Pattern系列 Operator 上

====================================================== 大家请把我的文章当参考,详细内容  还请参照 权威书籍  如果文中有错误和遗漏, 请指出,Aear会尽力更正, 谢谢!======================================================   废话不多说,这次讲的是 Operator over

杨德龙的专栏 889

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++基本功和 Design Pattern系列 ctor & dtor

最近实在是太忙了,无工夫写呀。只能慢慢来了。呵呵,今天Aear讲的是class.ctor 也就是constructor, 和  class.dtor, destructor. 相信大家都知道constructor 和 destructor是做什么用的,基本功能我就不废话了。下面先说效率的问题,让我们看个简单的例子:class SomeClass;   // forward declaratio

杨德龙的专栏 1万+

C++基本功和 Design Pattern系列(3) ctor & dtor

======================================================   大家请把我的文章当参考,详细内容  还请参照 权威书籍   programming language>如果文中有错误和遗漏,  请指出,Aear会尽力更正,

Programer From Scrach 706

C++基本功和 Design Pattern系列 Exception

说到Exception就要说下相关的Error Handling. 比较常用的Error Handling一般有如下几种类方式:    1. Return value    2. Assert    3. Debug Output    4. Exception相对于其他三种错误处理方式, Exception更加容易使用,而且使得错误代码相对集中,同时使得独立函数库的开发更加方便。同样,对于C

杨德龙的专栏 1128

C++基本功和 Design Pattern系列 Inheritance VS Delegation

http://blog.sina.com.cn/u/1261532101首先是const 和 reference的使用,这部分内容已经在C语言里说过,但是在C++里又有了一些扩展。 C++允许使用object作为参数传递,但是object有大有小。 比如下面一个object class:class CBitmap{public:    CBitmap();    ~CBitmap();

杨德龙的专栏 1967

C++基本功和 Design Pattern系列 virtual

关于virtual 一般有3种用法: virtual function, pure virtual function, 和 virtual inheritance. 今天就分别来讲讲这几种virtual.================ virtual function ================virtual函数是在类里边的一种特殊的函数,至于具体的含义,相信大家都知道,我就不多说了。

杨德龙的专栏 1596

C++基本功和 Design Pattern系列 Operator 下

继续上一章的内容,下面是经过调整后的Test Class代码:class Test {private:    int internalData;public:    // constructor and destructor    Test(int data = 0) : internalData(data) {};    Test(const Test & Para) : internalD

杨德龙的专栏 777

C++基本功和 Design Pattern系列 Leaf Class Design

所谓的Leaf Class, 就是在类层次中最低下一层,不能被其他任何的类所继承的。在Java中可以用final来表示。为了简化这一章的内容,我们不考虑template的情况,以及不考虑从其他的类继承而得到的leaf class的情况,这样就不用考虑overloading和 virtual的问题。另外,inline的使用在不在今天的文章范围内。关于template,inline和overloadi

杨德龙的专栏 1035

CPP design pattern Singleton

CPP design pattern Singleton

weixin_42244181的博客 426

C++基本功和 Design Pattern系列(1-3) - Inheritance VS Delegation

首先恭喜C++版开张,这样Aear又多了一个可以发表废话的地方。基本上C++基本功系列会是一个比较长的东西,因为C++和OO的内容太多,太难说的 清楚。Aear本人也不能保证所有的说的都正确,但是能发上来的内容都参照过 ISO, C++  programming language>>,以及其他的参考资料。 其 次,为什么Aear继续写基本语言的东西? Aear本来想写一些DirectX啊

haoxingfeng的专栏 1294

C++基本功和 Design Pattern系列(4-6)

======================================================  大家请把我的文章当参考,详细内容  还请参照 权威书籍   programming language>如果文中有错误和遗漏,  请指出,Aear会尽力更正, 谢谢! ====================================================== 最

haoxingfeng的专栏 803
上一篇: C++基本功和 Design Pattern系列(3) ctor & dtor
下一篇: GDB调试命令速查
BlueSy2008
博客等级 码龄20年 26粉丝 26原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值