见微知著——从自定义类型的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> &”!

时间: 2024-08-16 05:40:10

见微知著——从自定义类型的operator==说起的相关文章

map以自定义类型当Key

关于map的定义: template < class Key, class T, class Compare = less<Key>, class Allocator = allocator<pair<const Key,T> > > class map; 第一个template参数被当做元素的key,第二个template参数被当作元素的value.Map的元素型别Key和T,必须满足以下两个条件:1.key/value必须具备assignable(可赋值

Kubernetes operator 如何根据自定义类型生成响应的代码的?

分享这篇文章的主要目的, 是如何利用kubernetes来自定义类型,如SparkApplication,从而使用脚本,生成响应的代码的 这些代码是专门为自定义的类型SparkApplication对象服务的 0.最终效果如下: 1.测试环境说明 VMware + Centos 7 2.我们需要编写的文件,我测试需要3个(可能测试不够充分) doc.go register.go types.go 3.创建Go工程,利用k8s的特性自定义类型 types.go的主要内容,如下(你需要根据自己的实际

自定义类型转化

string num1 = "12"; string num2 = "13"; int num3; int num4 = 77; bool bo; num3 = int.Parse(Convert.ToString(num2)); bo = int.TryParse(Convert.ToString(num1), out num4); Console.Write(num3 +","+bo +","+num4 ); int.Tr

【map】【unordered_map】map和unordered_map中键类型为自定义类型的操作

STL中map的底层为红黑树,所以查找的时间复杂度为O(logn). unordered_map是根据哈希值(遇到哈希值相同时用==号比较)寻找键,所以时间复杂度为O(1). 键类型为自定义类型时,map需要重载键类型的<符号,unordered_map需要定义键类型的哈希函数(在类外定义),以及重载键类型的==符号. class person1 { public: string name; int age; person1(string s,int i):name(s),age(i){} //

利用implicit关键字做自定义类型隐式转换

在C#中,implicit关键字可以用来做自定义类型隐式转换.下面给个例子来说明. 先定义一个Point类,表示一个点: public class Point { public double X { get; set; } public double Y { get; set; } } 再在Point类中定义一个静态方法,用于由字符串隐式转换为Point类型: public class Point { public double X { get; set; } public double Y {

stl vector自定义类型的去重问题

最近项目遇到一个问题,有关stl vector自定义类型的去重问题. 背景:1.在一个vector中,存在大量元素拥有同一属性,而其他属性我们不关心,为了减少数据包大小,需要去重 2.此自定义类型不能去重载==操作符(公司代码规范等原因) 3.正常情况下,vector中对象是有序的(拥有同一属性的元素排在一起)                /*引起误解,后补充*/ 于是,花了十分钟撸出了下列代码原型. 1 #include <iostream> 2 #include <vector&g

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

版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QSet使用及Qt自定义类型使用QHash等算法     本文地址:http://techieliang.com/2017/12/580/ 文章目录 1. 介绍 2. 简单范例 3. 自定义类型 1. 介绍 Qt提供的一个单值的数学集合的快速查找容器,使用方式与QList相同,但其内元素不会有重复.详细说明见 官方文档 注意,此容器实现方式是基于哈希表,而不是红黑树,若使用自定义类必须提供对

priority_queue里面自定义类型的使用。

1 #include<iostream> 2 #include<queue> 3 using namespace std; 4 struct tree{ 5 int num; 6 string s; 7 tree(int x,string zfc) 8 { 9 num=x; 10 s=zfc; 11 } 12 friend bool operator>(const tree &a,const tree &b) 13 { 14 return a.num>b

springmvc 类型转换器 自定义类型转换器

自定义类型转换器的步骤: 1.定义类型转换器 2.类型转换器的注册(在springmvc配置文件处理) 来解决多种日期格式的问题: