今天打算用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==说起的更多相关文章

  1. map以自定义类型当Key

    关于map的定义: template < class Key, class T, class Compare = less<Key>, class Allocator = alloc ...

  2. 《精通C#》自定义类型转化-扩展方法-匿名类型-指针类型(11.3-11.6)

    1.类型转化在C#中有很多,常用的是int类型转string等,这些都有微软给我们定义好的,我们需要的时候直接调用就是了,这是值类型中的转化,有时候我们还会需要类类型(包括结构struct)的转化,还 ...

  3. 关于set或map的key使用自定义类型的问题

    我们都知道set或map的key使用自定义类型时必须重载<关系运算符 但是,还有一个条件,所调用重载的小于操作符,使用的对象必须是const 而对象调用的方法也必须是const的 1 #incl ...

  4. Qt之创建自定义类型

    摘要: 简述 当使用Qt创建用户界面时,特别是那些带有特殊控制和特征的界面时,开发者通常需要创建新数据类型来扩展或替换Qt现有的的值类型集合. 标准类型,比如:QSize.QColor和QString ...

  5. [转]std::set、自定义类型与比较函数

    转自:http://www.189works.com/article-42025-1.html 怎样在set中放入自定义类型?这个问题通过谷歌就可以得到不少答案:1.定义一个函数对象并在定义set的时 ...

  6. QSet使用及Qt自定义类型使用QHash等算法

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSet使用及Qt自定义类型使用QHash等算法     本文地址:http://techie ...

  7. Qt自定义类型使用QHash等算法(Qt已经自定义了34种类型,包括int, QString, QDate等基本数据类型)

    自定义类型 #include <QCoreApplication> #include <QSet> #include <QDebug> class testCust ...

  8. 在set中放入自定义类型

    这件事情的起因是在学习背包问题时突然想到了一种算法,分析了一下应该是n^2logn复杂度的,当然比dp慢.但是既然想到了就实现了下: #include<bits/stdc++.h> usi ...

  9. C#简单问题,不简单的原理:不能局部定义自定义类型(不含匿名类型)

    今天在进行代码测试时发现,尝试在一个方法中定义一个委托,注意是定义一个委托,而不是声明一个委托变量,在编写的时候没有报错,VS也能智能提示,但在编译时却报语法不完整,缺少方括号,但实际查询并没有缺少, ...

随机推荐

  1. 准确率(Accuracy), 精确率(Precision), 召回率(Recall)和F1-Measure(对于二分类问题)

    首先我们可以计算准确率(accuracy),其定义是: 对于给定的测试数据集,分类器正确分类的样本数与总样本数之比.也就是损失函数是0-1损失时测试数据集上的准确率. 下面在介绍时使用一下例子: 一个 ...

  2. 01-java技术体系基础

    java体系基础 理论 编程语言: 系统级: C, C++, go, erlang ... 应用级: C#, Java, Python, Perl, Ruby, php 虚拟机: jvm(java虚拟 ...

  3. SSM中(Spring-SpringMVC-Mybatis)(二:整合)

    使用Maven整合一个SSM,当然要配有Maven环境,Maven的环境配置自行百度,挺好配的 创建一个Maven项目以后,目录结构如图所示: 然后就是各部分配置: 首先pom导入依赖jar包: &l ...

  4. 一步步实现滑动验证码,Java图片处理关键代码

    最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低.当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本. ...

  5. Invalid bound statement (not found): com.shizongger.chapter2.mapper.UserMapper.insertUser 解决方案

    在配置MyBatis时报错信息如下: Invalid bound statement (not found): com.shizongger.chapter2.mapper.UserMapper.in ...

  6. MicroPython-TPYBoard固件编译教程

    本文主要介绍一下,在Linux环境下编译micropython固件的方法和流程. 首先,我们先来看一下MicroPython的源码结构. github地址:https://github.com/mic ...

  7. Spring框架入门之Spring简介

    一.Spring简介(由Rod Johnson创建的一个开源框架)        Spring是一个开放源代码的设计层面框架,他解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿 ...

  8. vue 设计日历表

    日历的功能,我们会经常用到,且逻辑比较复杂,小算法较多,花了半天时间写了个,特此详记. 先贴图 功能阐述:返回本月不多说,设置工作日和节假日是为了公司制度需要,后台会有假日表来记录. 为了适应于vue ...

  9. nodejs+express+mysql实现restful风格的增删改查示例

    首先,放上项目github地址:https://github.com/codethereforam/express-mysql-demo 一.前言 之前学的java,一直用的ssm框架写后台.前段时间 ...

  10. 【括号问题】$("li:lt(" + (idx + 1) + ")") 手风琴效果注意事项

    $("li:lt(" + (idx + 1) + ")").each(function(i){ 注意,这里必须要加括号,是因为如果不加,idx与前面  &quo ...