见微知著——从自定义类型的operator==说起
今天打算用C++模拟一下Java的Object对象。需求很简单,通过一个自定义用户类型包装一个内建类型,并提供equals、hashCode、=和== 4种函数。
源码如下:
#pragma once
#ifndef ENTITY_H_
#define ENTITY_H_
#include <functional>
template<typename T>
class Entity {
private:
T obj;
Entity(const Entity&);
public:
Entity(T t) :obj(t) {}; bool equals(Entity& other) {
std::hash<T> tohash;
return tohash(obj) == other.hashCode();
} size_t hashCode() {
std::hash<T> tohash;
return tohash(obj);
} Entity<T>& operator=(const Entity& rv) {
obj = rv.obj;
return *this;
} friend bool operator==(const Entity& left, const Entity& right) {
return left.hashCode() == right.hashCode();
}
}; #endif // !ENTITY_H_
C++11 提供了Hash方法正好拿来使用,可是在测试==的时候却发现编译器报错:“size_t Entity<int>::hashCode(void)”: 不能将“this”指针从“const Entity<int>”转换为“Entity<int> &”。说实话,平时Java用习惯了,猛然看见C++的报错信息真是一脸懵逼。后来在网上查了一些资料逐渐明白了个中缘由。
首先修改代码:
size_t hashCode() const {
std::hash<T> tohash;
return tohash(obj);
}
测试通过!做法很简单,但是要说明清楚这个问题,我们还得从对象方法与函数的区别谈起。
1. 函数与方法
函数是一个很原始的概念,在古代面向对象的语言还没有诞生。大家为了封装一些公共算法发明了函数这个概念,通常是根据实参经过函数体返回一个计算结果,并且实参要和形参对应。后来,面向对象的语言出现了,大家开始考虑让对象实施某些行为,这就是——方法。本质上,函数叫function和方法叫method。对象方法之于普通函数的最大区别是,它可以直接访问对象内部的成员属性(field)。在Java中我们通过this.field的方式就能够访问,在C++中更普遍的做法是this->field。这里就很奇怪了,为什么在method内部能直接使用this呢?原因是语言在编译过程中,编译器将对象(this)作为参数置入了method中。因此实际上,method的真实形象应该是这样的:method(this, args)。熟悉面向过程语言特性的朋友一定清楚,如果不用面向对象的思想实际上也可以用function模拟method,即也是将对象本身作为参数传递给function。
2. function(args) const
const blob b(2);
这里,b是类型blob的一个const对象。它的构造函数被调用,并且参数为“2”。由于编译器强调对象为const,因此它必须保证对象的数据成员(fields)在其生命周期内不被改变。然而,仅仅是在类声明中给出const还不能保证成员函数按声明的方式去做。所以,编译器会强制程序员在定义函数时重申const。这就是function(args) const的由来。
3. 结论
在明白了以上两点以后,我们再回到本例中。由于operator==(const Left& lv, const Right& rv)在函数中要求提供的两个参数对象都必须是const类型。因此在整个函数体中,这些对象执行的方法也必须是const类型。然而现在我们知道成员函数会隐式的调用对象本身,换句话说hashCode()方法会分别调用Left与Right,而这个方法并没有被重申为const。这就出现了开头看到的那段异常:“size_t Entity<int>::hashCode(void)”: 不能将“this”指针从“const Entity<int>”转换为“Entity<int> &”!
见微知著——从自定义类型的operator==说起的更多相关文章
- map以自定义类型当Key
关于map的定义: template < class Key, class T, class Compare = less<Key>, class Allocator = alloc ...
- 《精通C#》自定义类型转化-扩展方法-匿名类型-指针类型(11.3-11.6)
1.类型转化在C#中有很多,常用的是int类型转string等,这些都有微软给我们定义好的,我们需要的时候直接调用就是了,这是值类型中的转化,有时候我们还会需要类类型(包括结构struct)的转化,还 ...
- 关于set或map的key使用自定义类型的问题
我们都知道set或map的key使用自定义类型时必须重载<关系运算符 但是,还有一个条件,所调用重载的小于操作符,使用的对象必须是const 而对象调用的方法也必须是const的 1 #incl ...
- Qt之创建自定义类型
摘要: 简述 当使用Qt创建用户界面时,特别是那些带有特殊控制和特征的界面时,开发者通常需要创建新数据类型来扩展或替换Qt现有的的值类型集合. 标准类型,比如:QSize.QColor和QString ...
- [转]std::set、自定义类型与比较函数
转自:http://www.189works.com/article-42025-1.html 怎样在set中放入自定义类型?这个问题通过谷歌就可以得到不少答案:1.定义一个函数对象并在定义set的时 ...
- QSet使用及Qt自定义类型使用QHash等算法
版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSet使用及Qt自定义类型使用QHash等算法 本文地址:http://techie ...
- Qt自定义类型使用QHash等算法(Qt已经自定义了34种类型,包括int, QString, QDate等基本数据类型)
自定义类型 #include <QCoreApplication> #include <QSet> #include <QDebug> class testCust ...
- 在set中放入自定义类型
这件事情的起因是在学习背包问题时突然想到了一种算法,分析了一下应该是n^2logn复杂度的,当然比dp慢.但是既然想到了就实现了下: #include<bits/stdc++.h> usi ...
- C#简单问题,不简单的原理:不能局部定义自定义类型(不含匿名类型)
今天在进行代码测试时发现,尝试在一个方法中定义一个委托,注意是定义一个委托,而不是声明一个委托变量,在编写的时候没有报错,VS也能智能提示,但在编译时却报语法不完整,缺少方括号,但实际查询并没有缺少, ...
随机推荐
- Mongodb集群【三】
Mongodb常用三种集群 1 主从(Master/Slave) 不推荐,但是mongodb依然保留有.一主多从,不支持链式结构.简单主从,没有裁仲者不能自动恢复. 2 副本集(Relica Set) ...
- 关于dl dt dd 文字过长换行在移动端显示对齐的探讨总结
关于dl dt dd 文字过长换行在移动端显示对齐的探讨总结 <dl> <dt>抵押房产:</dt> <dd>1.北京市大兴区兴华大街丽园小区3单大兴 ...
- JQuery.lazyload 图片延迟加载
1.引入 jquery.lazyload.js 2. 延时加载的方式 <script type="text/javascript"> $(function() { ...
- 架构师之路->架构师思维的培养
公司的CMS(综合赋码管理系统)是WINFORM的CS架构.这套系统的架构师换了3届,到现在已经几年没有架构师了.本来入职时,岗位目标就是这个“自动化架构师”. 后来和领导达成共识先争取成为储备架构师 ...
- PHP中域名绑定
1.如果是集成环境,比如phpstudy则可以直接在工具中点击其他选项菜单->站点域名管理填好对应的域名和站点目录后点击新增,然后点击保存设置并生成配置文件,然后再打开hosts文件,增加对应的 ...
- win10 uwp 横向 AppBarButton
一般看到的 AppBarButton 都是图片在上面,文字在下面,是否可以更改让文字在和图片相同的位置?本文告诉大家如何做出横向的 AppBarButton 把图标和文本放在一起. 如果需要添加 Ap ...
- 【Docker】安装Docker及基本使用
该文以CentOS系统为例,介绍Docker安装及基本使用.为了简化安装流程,Docker 官方提供了一套安装脚本,CentOS 系统上可以使用这套脚本安装: curl -sSL https://ge ...
- naturalWidth 与 naturalHeight
在HTML 5中,新增加了两个用来判断图片的宽度和高度的属性(图片原始大小),分别为 naturalWidth 和naturalHeight属性,例子如下: 注意问题: - 图片没有加载的时候 值为0 ...
- Java与算法之(10) - 希尔排序
希尔排序是插入排序的一种,是直接插入排序的改进版本. 对于上节介绍的直接插入排序法,如果数据原来就已经按要求的顺序排列,则在排序过程中不需要进行数据移动操作,即可得到有序数列.但是,如果最初的数据是按 ...
- Cnm%(个人模版)
Cnm%: #include<stdio.h> #include<string.h> #include<vector> using namespace std; # ...