見微知著——從自定義類型的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> &”!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM