c++类成员函数重载常量与非常量版本时避免代码重复的一种方法
c++有时候需要为类的某个成员函数重载常量与非常量的版本,定义常量版本是为了保证该函数可作用于常量类对象上,并防止函数改动对象内容。但有时两个版本的函数仅仅是在返回的类型不同,而在返回前做了大量相同的工作,那么代码会有大量重复,由此也会带来编译时间和代码膨胀等开销。例如下面的类成员函数:
#include <string> class Test
{
using size_type = std::string::size_type;
public:
const char & operator[](size_type index) const;
char & operator[](size_type index);
private:
std::string str;
}; const char & Test::operator[](size_type index) const
{
//...
//...
//要执行的操作
return str[index];
} char & Test::operator[](size_type index)
{
//...
//...
//要执行的操作
return str[index];
}
虽然完全可以将执行的相同的动作写在一个新的成员函数里并将其定义为私有的,但这样仍然有函数调用和返回值的重复。一种可行的方法是让两个函数的其中一个调用另一个,如下所示:
class Test
{
using size_type = std::string::size_type;
public:
const char & operator[](size_type index) const;
char & operator[](size_type index);
private:
std::string str;
}; const char & Test::operator[](size_type index) const
{
//...
//...
//要执行的操作
return str[index];
} char & Test::operator[](size_type index)
{
return const_cast<char &>(static_cast<const Test &>(*this)[index]);
}
非常量版本调用了常量版本,在这过程中进行了两次转型:
①static_cast<const Test &>(*this),将非常量类型的Test对象转换成常量类型(const)的Test对象,即把<Test &>类型的*this转换成<const Test &>类型,再调用常量版本的下标运算符。若没有进行转换直接调用下标运算符,等于函数递归调用自己,将会进入死循环。
②const_cast<char &>(),上一步的static_cast<const Test &>(*this)[index]调用了常量版本的下标运算符,返回的类型为const char &,接下来便利用const_cast去除返回值的const属性。
附注1:
应该注意函数调用的主宾关系:非常量版本调用常量版本并进行类型转换。反过来的做法则是一种错误的行为,常量版本成员函数不会改变对象的逻辑状态,而在常量版本中调用非常量版本则存在着可能改变对象的风险。实际上这样的代码若要通过编译,需要用const_cast去除*this的const属性,这显然是一种不安全的行为。相反,非常量版本成员函数本来就可以改动对象,因为在函数内部调用常量版本并不会有风险。
c++类成员函数重载常量与非常量版本时避免代码重复的一种方法的更多相关文章
- 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)
在C++中,成员函数的指针是个比较特殊的东西.对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用.但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法. ...
- C++之static类成员,static类成员函数
0.static修饰类中成员,表示类的共享数据 1.static类成员 在C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处在.static类 ...
- 并发编程: c++11 thread(Func, Args...)利用类成员函数创建线程
c++11是VS2012后支持的新标准,为并发编程提供了方便的std::thread. 使用示例: #include <thread> void thread_func(int arg1, ...
- C++ 面向对象 类成员函数this指针
每个类成员函数都只涉及一个对象, 即调用它的对象. 但有时候方法可能涉及到两个对象, 在这种情况下需要使用C++ 的 this 指针 假设将方法命名为topval(), 则函数调用stock1.top ...
- 【非原创】C++类成员函数的重载、覆盖和隐藏
链接:https://www.nowcoder.com/questionTerminal/266d3a6d4f1b436aabf1eff3156fed95来源:牛客网 题目:类成员函数的重载.覆盖和隐 ...
- 重载运算符:类成员函数or友元函数
类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...
- C++类成员函数的重载、覆盖和隐藏区别?
C++类成员函数的重载.覆盖和隐藏区别? a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.b.覆盖是指派生类函数覆 ...
- C++:类成员函数的重载、覆盖和隐藏区别?
#include <iostream> class A { public: void func() { std::cout << "Hello" <& ...
- 类成员函数的重载、覆盖和隐藏区别 (C++)(转)
类成员函数的重载.覆盖和隐藏区别 (C++) 这是本人第一次写博客,主要是想记录自己的学习过程.心得体会,一是可以方便以后回顾相关知识,二是可以与大家相互学习交流. 关于C++中类成员函数的重载. ...
随机推荐
- (转)在GitHub多个帐号上添加SSH公钥
GitHub后台可以添加多个SSH Keys,但是同一个SSH Keys只能在添加在一个帐号上(添加时提示“Key is already in use”).理由很容易想到,SSH公钥使用时相当于用户名 ...
- JS随机数种子
JS随机数种子 1 试着想一下,如果在某一个场景,我们做一个游戏,用户玩到一半的时候退出了,这样 用户下次进来可以选择继续上一次的进度继续玩,那么现在问题来了:用户玩 的进度以及用户的积分等简单的描述 ...
- SimpleDateFormat实现String与Date之间的转换
基本用法: java.text.SimpleDateFormat format=new SimpleDateFormat("yyyy-MM-dd"); java.util.Date ...
- SQLServer cast()函数
语法: CAST (expression AS data_type) 参数说明: expression:任何有效的SQLServer表达式. AS:用于分隔两个参数,在AS之前的是要处理的数据,在AS ...
- router基本使用
摘自:https://blog.csdn.net/qq_39894133/article/details/78992923 1.vue2 路由的使用流程: 1.vue2中的路由定义层:<rout ...
- 使用MongoVUE无法添加Collection
说明: 问题MongoDB版本为3.2,MongoVUE 1.6.9 问题: 在数据库中添加集合不可用. 解决方法: MongoDB版本换成2 或者 切换存储引擎: 从MongoDB 3.2 版本开始 ...
- Mac下将C程序创建为动态链接库再由另一个C程序调用
写C的时候需要调用之前的一个C程序,想用动态链接库的方式.Mac下的动态链接库是dylib,与Linux下的.os或Windows下的.dll不同.由于之前没有接触过,所以翻了大量的博客,然而在编译过 ...
- Ubuntu16.04 国内更新源
在修改source.list之前要先备份 sudo cp /etc/apt/sources.list /etc/apt/sources.list.bak 替换内容到source.list中 阿里云源: ...
- G_M_C_美食节
美食节 题解:学习了动态加边,可以说是进一步理解了网络流.具体思路就是考虑每一道菜,如果这是该位厨师最后一次做,那么等待时间就是做这道菜的时间,如果是倒数第二次做,就要两倍时间(目前做了一次,后面还有 ...
- 简单实现Ubuntu16.04 + caffe2 + CUDA9.0 + cuDNN8.0
在Ubuntu16.04 CUDA9.0 cuDNN8.0的环境下安装caffe2 本博客比较简单,cuda9.0 cudnn8.0部分请看上一篇博客,其中详细讲了: 如何安装驱动 安装cuda 安装 ...