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++类成员函数重载常量与非常量版本时避免代码重复的一种方法的更多相关文章

  1. 直接调用类成员函数地址(用汇编取类成员函数的地址,各VS版本还有所不同)

    在C++中,成员函数的指针是个比较特殊的东西.对普通的函数指针来说,可以视为一个地址,在需要的时候可以任意转换并直接调用.但对成员函数来说,常规类型转换是通不过编译的,调用的时候也必须采用特殊的语法. ...

  2. C++之static类成员,static类成员函数

    0.static修饰类中成员,表示类的共享数据 1.static类成员 在C++primer里面说过,static类成员不像普通的类数据成员,static类数据成员独立于一切类对象处在.static类 ...

  3. 并发编程: c++11 thread(Func, Args...)利用类成员函数创建线程

    c++11是VS2012后支持的新标准,为并发编程提供了方便的std::thread. 使用示例: #include <thread> void thread_func(int arg1, ...

  4. C++ 面向对象 类成员函数this指针

    每个类成员函数都只涉及一个对象, 即调用它的对象. 但有时候方法可能涉及到两个对象, 在这种情况下需要使用C++ 的 this 指针 假设将方法命名为topval(), 则函数调用stock1.top ...

  5. 【非原创】C++类成员函数的重载、覆盖和隐藏

    链接:https://www.nowcoder.com/questionTerminal/266d3a6d4f1b436aabf1eff3156fed95来源:牛客网 题目:类成员函数的重载.覆盖和隐 ...

  6. 重载运算符:类成员函数or友元函数

    类成员函数: bool operator ==(const point &a)const { return x==a.x; } 友元函数: friend bool operator ==(co ...

  7. C++类成员函数的重载、覆盖和隐藏区别?

    C++类成员函数的重载.覆盖和隐藏区别? a.成员函数被重载的特征:(1)相同的范围(在同一个类中):(2)函数名字相同:(3)参数不同:(4)virtual 关键字可有可无.b.覆盖是指派生类函数覆 ...

  8. C++:类成员函数的重载、覆盖和隐藏区别?

    #include <iostream> class A { public: void func() { std::cout << "Hello" <& ...

  9. 类成员函数的重载、覆盖和隐藏区别 (C++)(转)

    类成员函数的重载.覆盖和隐藏区别 (C++)   这是本人第一次写博客,主要是想记录自己的学习过程.心得体会,一是可以方便以后回顾相关知识,二是可以与大家相互学习交流. 关于C++中类成员函数的重载. ...

随机推荐

  1. Java线程池ThreadPoolExecuter:execute()原理

    一.线程池执行任务的流程 如果线程池工作线程数<corePoolSize,创建新线程执行task,并不断轮训t等待队列处理task. 如果线程池工作线程数>=corePoolSize并且等 ...

  2. php获取目录下所有文件路径(递归)

    <?php function tree(&$arr_file, $directory, $dir_name='') { $mydir = dir($directory); while($ ...

  3. IP地址与子网掩码的计算

    128.0.0.0=1 192.0.0.0=2224.0.0.0=3 240.0.0.0=4 248.0.0.0=5 252.0.0.0=6 254.0.0.0=7 255.0.0.0=8255.12 ...

  4. Vector、List、LinkedList

    Vector 遍历 Vector<String> vestor =new Vector<String>(); vestor.add("qq"); vesto ...

  5. ZW团队:IN_OUT传播模型简介

    传统媒体,网络媒体的整合推广,我曾经提出过一个:Tn-Out模式 In-Out是NBA的篮球术语,你自己百度下 传统媒体承担"IN"的角色,负责传播的深度和建立公信力 网络媒体充当 ...

  6. MapReduce: map读取文件的过程

    我们的输入文件 hello0, 内容如下: xiaowang 28 shanghai@_@zhangsan 38 beijing@_@someone 100 unknown 逻辑上有3条记录, 它们以 ...

  7. springcloud12---sidecar

    Sidecar:异构平台整合.做了一个桥 package com.itmuch.cloud; import org.springframework.boot.SpringApplication; im ...

  8. MVC相关资料收集

    文章: 谈谈service层在mvc框架中的意义和职责 Model–view–controller - Wikipedia MVC Architecture - Google Chrome - Chr ...

  9. 简单了解下CGI、FastCGI和php-fpm的概念和区别和运行原理

    什么是CGI? CGI(Common Gateway Interface),公共网关接口,它是Web服务器与外部应用程序(CGI程序)之间传递信息的接口标准.通过CGI接口,Web服务器就能够获取客户 ...

  10. 现在 做java 构架(RabbitMQ redis mysql )之类的

    现在 做java 构架(RabbitMQ redis mysql )之类的