类运算符重载的实验

前言

今天向工程中添加了一个.h, 里面包含了一个结构, 结构中定义了运算符(> <)重载. 没特别的, 在debian8 + c++98下编译不过。实在没看出来是哪里有问题. 于是将.h分成了.h +.cpp, 这回,编译器报错的定位容易找了。找到以下问题:

  • 在一个函数的条件判断中,少加了后面的括弧

  • stl::map中用类或结构作为key时, 类中要重载 < 运算符

  • 重载的运算符要有const限定
    e.g. bool operator < (const TAG_IP_ADDR_ARY& src) const;

  • 在const限定的成员函数中调用的其他成员函数, 也必须有const限定
    e.g. bool is_ipv4() const;

对于较简单的结构或类, 将内容都写入.h, 用起来是方便,但是如果编译不过,报错点也不太好找,眼神要特别的好。

demo工程下载点

src_test_class_operator_overload.7z

实验

// @file main.cpp

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h> // daemon
#include <signal.h>
#include <time.h>

#include <map>

#include "my_syslog.h"
#include "TAG_IP_ADDR_ARY.h"

#ifndef SAFE_DELETE
#define SAFE_DELETE(p) \
    if (NULL != (p)) { \
        delete (p); \
        (p) = NULL; \
    }
#endif // #ifndef SAFE_DELETE

#define LINE80 "--------------------------------------------------------------------------------"

void init(const char* psz_log_owner_name);
void uninit();
void proc_sig_term(int num);
int fn_test();

int main(int argc, char** argv)
{
    char sz_buf[1024] = {'\0'};

#ifdef MAKE_FILE_MACRO__BIN_NAME
    sprintf(sz_buf, "%s", MAKE_FILE_MACRO__BIN_NAME);
    init(sz_buf);
    MYLOG_D("MAKE_FILE_MACRO__BIN_NAME = [%s]", MAKE_FILE_MACRO__BIN_NAME);
#else
    init(NULL);
#endif // #ifdef MAKE_FILE_MACRO__BIN_NAME

    fn_test();
    uninit();

    MYLOG_D("THE END");
    return EXIT_SUCCESS;
}

int fn_test()
{
    MYLOG_D(">> fn_test()");
    TAG_IP_ADDR_ARY ipv4_a;
    TAG_IP_ADDR_ARY ipv4_b;
    TAG_IP_ADDR_ARY ipv6_a;
    TAG_IP_ADDR_ARY ipv6_b;
    uchar sz_ip[16] = {
        0xaa, 0xab, 0xba, 0xbb, 
        0xaa, 0xab, 0xba, 0xbb, 
        0xaa, 0xab, 0xba, 0xbb, 
        0xaa, 0xab, 0xba, 0xbb};

    ipv4_a.set_ipv4(0xaabbccdd);
    ipv4_b.set_ipv4(0xaabbccee);

    ipv6_a.set_ipv6(sz_ip, sizeof(sz_ip));
    sz_ip[14] = 0xaa;
    ipv6_b.set_ipv6(sz_ip, sizeof(sz_ip));

    // case ipv4
    printf("%s\n", LINE80);
    if (ipv4_a > ipv4_b) {
        printf("ipv4_a > ipv4_b\n");
    }

    if (ipv4_a >= ipv4_b) {
        printf("ipv4_a >= ipv4_b\n");
    }

    if (ipv4_a < ipv4_b) {
        printf("ipv4_a < ipv4_b\n");
    }

    if (ipv4_a <= ipv4_b) {
        printf("ipv4_a <= ipv4_b\n");
    }

    if (ipv4_a == ipv4_b) {
        printf("ipv4_a == ipv4_b\n");
    }

    if (ipv4_a != ipv4_b) {
        printf("ipv4_a != ipv4_b\n");
    }

    // case ipv6
    printf("%s\n", LINE80);
    if (ipv6_a > ipv6_b) {
        printf("ipv6_a > ipv6_b\n");
    }

    if (ipv6_a >= ipv6_b) {
        printf("ipv6_a >= ipv6_b\n");
    }

    if (ipv6_a < ipv6_b) {
        printf("ipv6_a < ipv6_b\n");
    }

    if (ipv6_a <= ipv6_b) {
        printf("ipv6_a <= ipv6_b\n");
    }

    if (ipv6_a == ipv6_b) {
        printf("ipv6_a == ipv6_b\n");
    }

    if (ipv6_a != ipv6_b) {
        printf("ipv6_a != ipv6_b\n");
    }

    // case ipv4 and ipv6
    // 不同类型的数据是没有必要比较的, 这个测试没意义
    printf("%s\n", LINE80);
    if (ipv4_a > ipv6_b) {
        printf("ipv4_a > ipv6_b\n");
    }

    if (ipv4_a >= ipv6_b) {
        printf("ipv4_a >= ipv6_b\n");
    }

    if (ipv4_a < ipv6_b) {
        printf("ipv4_a < ipv6_b\n");
    }

    if (ipv4_a <= ipv6_b) {
        printf("ipv4_a <= ipv6_b\n");
    }

    if (ipv4_a == ipv6_b) {
        printf("ipv4_a == ipv6_b\n");
    }

    if (ipv4_a != ipv6_b) {
        printf("ipv4_a != ipv6_b\n");
    }

    // case map key use class
    printf("%s\n", LINE80);
    std::map<TAG_IP_ADDR_ARY, int> map_ip;
    std::map<TAG_IP_ADDR_ARY, int>::iterator it;
    map_ip.insert(std::make_pair(ipv4_a, 1));

    it = map_ip.find(ipv4_a);
    if (it != map_ip.end()) {
        printf("find ipv4_a\n");
    }

    it = map_ip.find(ipv6_a);
    if (it != map_ip.end()) {
        printf("find ipv6_a\n");
    }

    return 0;
}

/** run result
--------------------------------------------------------------------------------
ipv4_a < ipv4_b
ipv4_a <= ipv4_b
ipv4_a != ipv4_b
--------------------------------------------------------------------------------
ipv6_a > ipv6_b
ipv6_a >= ipv6_b
ipv6_a != ipv6_b
--------------------------------------------------------------------------------
ipv4_a < ipv6_b
ipv4_a != ipv6_b
--------------------------------------------------------------------------------
find ipv4_a
*/

void init(const char* psz_log_owner_name)
{
    int i = 0;

    // daemon(0, 0);

    ns_syslog::open_syslog((NULL != psz_log_owner_name) ? psz_log_owner_name : "ns_syslog");

    ns_syslog::g_log_condition.b_EMERG = false;
    ns_syslog::g_log_condition.b_CRIT = true;
    ns_syslog::g_log_condition.b_ALERT = true;
    ns_syslog::g_log_condition.b_ERR = true;
    ns_syslog::g_log_condition.b_WARNING = true;
    ns_syslog::g_log_condition.b_NOTICE = true;
    ns_syslog::g_log_condition.b_INFO = true;
    ns_syslog::g_log_condition.b_DEBUG = true;

    ns_syslog::set_log_level(
        ns_syslog::g_log_condition.b_EMERG, 
        ns_syslog::g_log_condition.b_ALERT,
        ns_syslog::g_log_condition.b_CRIT,
        ns_syslog::g_log_condition.b_ERR,
        ns_syslog::g_log_condition.b_WARNING,
        ns_syslog::g_log_condition.b_NOTICE,
        ns_syslog::g_log_condition.b_INFO,
        ns_syslog::g_log_condition.b_DEBUG);

    // clear screen (print 25 empty line)
    for (i = 0; i < 25; i++) {
        MYLOG_D("");
    }

    signal(SIGTERM, proc_sig_term);
}

void uninit()
{
    ns_syslog::close_syslog();
}

void proc_sig_term(int num)
{
    MYLOG_D("SIGTERM = %d, num = %d", SIGTERM, num);
    MYLOG_D("maybe can do some clean task before quit");
    exit(1);    
}

// @file \src\TAG_IP_ADDR_ARY.h

#ifndef __TAG_IP_ADDR_ARY_H__
#define __TAG_IP_ADDR_ARY_H__

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <string>

#ifndef uchar
typedef unsigned char uchar;
#endif // #ifndef uchar

#pragma pack(push)
#pragma pack(1)

// 像使用结构一样使用类
// 要像结构一样的保存类的内容(基本数据类型), 不能有虚表
class TAG_IP_ADDR_ARY {
public:
    // 没有一种内建数据类型能表示128bits, 所以用char[16]数组来表示ipv6的ip地址
    uchar ip_ary[16];
    uint u_hash;

    TAG_IP_ADDR_ARY();
    ~TAG_IP_ADDR_ARY(); // non virtual deconsturct fun

    // 运算符参数重载时, 如果使用了stl中的find(间接), 那么运算符重载要有const限定
    // 在const限定的成员函数中调用其他成员函数, 那些成员函数也要有const限定
    bool operator < (const TAG_IP_ADDR_ARY& src) const;
    bool operator <= (const TAG_IP_ADDR_ARY& src) const;

    bool operator > (const TAG_IP_ADDR_ARY& src) const;
    bool operator >= (const TAG_IP_ADDR_ARY& src) const;

    bool operator != (const TAG_IP_ADDR_ARY& src) const;
    bool operator == (const TAG_IP_ADDR_ARY& src) const;

    // member function imp, all member function not allow to virtual 
    bool is_valid() const;
    bool is_ipv4() const;

    void clear();
    void set_ipv4(uint u_ipv4);
    void set_ipv6(uchar* psz_ipv6, int len_ipv6);
    void set_ip(const char* psz_ip);
    std::string to_string() const;

    uint ipv4_to_uint();
    std::string ipv6_to_string();

    uint elf_hash(uchar* buf, int len);
    void calc_hash();
    uint hash();

    // '0'~'9' 'a'~'f' 'A'~'F' to 0~15
    uchar get_ascii_char_value(char c_in);
};

#pragma pack(pop)


#endif // #ifndef __TAG_IP_ADDR_ARY_H__

// @file \src\TAG_IP_ADDR_ARY.cpp

#include "TAG_IP_ADDR_ARY.h"

TAG_IP_ADDR_ARY::TAG_IP_ADDR_ARY() {
    clear();
}

TAG_IP_ADDR_ARY::~TAG_IP_ADDR_ARY() {
    clear();
}

void TAG_IP_ADDR_ARY::clear() {
    memset(ip_ary, 0, sizeof(ip_ary));
    calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}

void TAG_IP_ADDR_ARY::set_ipv4(uint u_ipv4) {
    clear();
    // copy u_ipv4 to ip[12] ~ ip[15]
    memcpy((ip_ary + 12), &u_ipv4, sizeof(uint));
    calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}

void TAG_IP_ADDR_ARY::set_ipv6(uchar* psz_ipv6, int len_ipv6) {
    clear();
    if ((NULL == psz_ipv6) || ((int)sizeof(ip_ary) != len_ipv6)) {
        return;
    }

    memcpy(ip_ary, psz_ipv6, len_ipv6);
    calc_hash(); // 只有在数据初始化或设置新值时, 计算一次hash
}

void TAG_IP_ADDR_ARY::set_ip(const char* psz_ip) {
    int i = 0;
    size_t nlen = 0;
    uchar uc_tmp[16];
    uchar uc_now = '\0';
    char c_tmp = '\0';
    uint u_ipv4 = 0;
    uchar ip_ary[16] = {'\0'};
    int pos_index = 0;
    int ary_index = 0;

    memset(uc_tmp, 0, sizeof(uc_tmp));      
    if (NULL == psz_ip) {
        return;
    }

    nlen = sizeof(psz_ip);
    if (NULL != strchr(psz_ip, '.')) {
        // ipv4 string
        // 192.168.4.11
        u_ipv4 = 0;
        uc_now = 0;
        for (i = 0; i < (int)nlen; i++) {
            c_tmp = psz_ip[i];
            if ('.' == c_tmp) {
                u_ipv4 <<= 8;
                u_ipv4 += uc_now;
                uc_now = 0;
                continue;
            } else {
                uc_now *= 10;
                uc_now += get_ascii_char_value(c_tmp);
            }
        }

        set_ipv4(u_ipv4);
    } else if (NULL != strchr(psz_ip, ':')) {
        // 在实现都在.h中实现时
        // 有编译报错时, 上面的条件右面少了一个')', 导致编译的时候各种错
        // 因为找不到是哪里有问题, 拆开成.h, .cpp实现, 这时编译器报错信息就比较好定位了

        // ipv6 string
        // fd15:4ba5:5a2b:1002:20c:29ff:fe89:e2cd
        uc_now = 0;
        pos_index = 0;
        memset(ip_ary, 0, sizeof(ip_ary));
        for (i = 0; i < (int)nlen; i++) {
            c_tmp = psz_ip[i];
            if (':' == c_tmp) {
                continue;
            } else {
                uc_now <<= 4;
                uc_now += get_ascii_char_value(c_tmp);
                pos_index++;
                if (2 == pos_index) {
                    if (ary_index < (int)sizeof(ip_ary)) {
                        ip_ary[ary_index++] = uc_now;
                    }
                    uc_now = 0;
                }
            }
        }

        set_ipv6(ip_ary, (int)sizeof(ip_ary));
    }
}

bool TAG_IP_ADDR_ARY::is_valid() const {
    // 是否有效
    // 如果不为全0, 就有效
    int i = 0;
    const uint zero = 0;

    for (i = 0; i < 4; i++) {
        if (0 != memcmp(ip_ary + i * sizeof(uint), &zero, sizeof(uint))) {
            return true; // 非空为有效
        }

    }

    return false;
}

bool TAG_IP_ADDR_ARY::is_ipv4() const {
    // 前12个字节为0, 就是ipv4
    int i = 0;
    const uint zero = 0;

    for (i = 0; i < 3; i++) {
        if (0 != memcmp(ip_ary + i * sizeof(uint), &zero, sizeof(uint))) {
            return false; // 非空为ipv6
        }
    }

    return true;
}

std::string TAG_IP_ADDR_ARY::to_string()   const {
    std::string rc = "";
    char sz_buf[0x100] = {'\0'};

    if (is_valid()) {
        if (is_ipv4()) {
            sprintf(sz_buf, 
                "%d.%d.%d.%d%c",
                ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
                '\0');
        } else {
            sprintf(sz_buf, 
                "%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X%c",
                ip_ary[0], ip_ary[1], ip_ary[2], ip_ary[3],
                ip_ary[4], ip_ary[5], ip_ary[6], ip_ary[7],
                ip_ary[8], ip_ary[9], ip_ary[10], ip_ary[11],
                ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
                '\0');
        }

        rc = sz_buf;
    }

    return rc;
}

std::string TAG_IP_ADDR_ARY::ipv6_to_string()
{
    std::string rc = "";
    char sz_buf[0x100] = {'\0'};

    if (is_valid()) {
        if (is_ipv4()) {
        } else {
            sprintf(sz_buf, 
                "%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X:%2.2X%2.2X%c",
                ip_ary[0], ip_ary[1], ip_ary[2], ip_ary[3],
                ip_ary[4], ip_ary[5], ip_ary[6], ip_ary[7],
                ip_ary[8], ip_ary[9], ip_ary[10], ip_ary[11],
                ip_ary[12], ip_ary[13], ip_ary[14], ip_ary[15],
                '\0');
        }

        rc = sz_buf;
    }

    return rc;
}

uint TAG_IP_ADDR_ARY::ipv4_to_uint()
{
    uint rc = 0;

    if (is_valid() && is_ipv4()) {
        rc = *(uint*)&ip_ary[12];
    }

    return rc;
}

uint TAG_IP_ADDR_ARY::elf_hash(uchar* buf, int len)
{
    // elf hash alg
    uint rc = 0;
    uint x = 0;

    if (NULL == buf) {
        return rc;
    }

    while (len > 0)
    {
        rc = (rc << 4) + *buf;
        x = rc & 0xf0000000;
        if (0 != x) {
            rc ^= (x >> 24); // 影响5-8位, 杂糅一次 
            rc &= ~x; // 清空高四位 
        }

        buf++;
        len--;
    }

    return (rc & 0x7fffffff);
}

void TAG_IP_ADDR_ARY::calc_hash()
{
    u_hash = elf_hash(ip_ary, (int)sizeof(ip_ary));
}

uint TAG_IP_ADDR_ARY::hash()
{
    return u_hash;
}

bool TAG_IP_ADDR_ARY::operator < (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] < src.ip_ary[i]) {
                return true;
            } else if (this->ip_ary[i] > src.ip_ary[i]) {
                return false;
            }
        }
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] < src.ip_ary[i]) {
                return true;
            } else if (this->ip_ary[i] > src.ip_ary[i]) {
                return false;
            }
        }
    }

    return false;
}

bool TAG_IP_ADDR_ARY::operator <= (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] > src.ip_ary[i]) {
                return false;
            }
        }
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] > src.ip_ary[i]) {
                return false;
            }
        }
    }

    return true;
}

bool TAG_IP_ADDR_ARY::operator > (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] > src.ip_ary[i]) {
                return true;
            } else if (this->ip_ary[i] < src.ip_ary[i]) {
                return false;
            }
        }
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] > src.ip_ary[i]) {
                return true;
            } else if (this->ip_ary[i] < src.ip_ary[i]) {
                return false;
            }
        }
    }

    return false;
}

bool TAG_IP_ADDR_ARY::operator >= (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] < src.ip_ary[i]) {
                return false;
            }
        }
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] < src.ip_ary[i]) {
                return false;
            }
        }
    }

    return true;
}

bool TAG_IP_ADDR_ARY::operator != (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] != src.ip_ary[i]) {
                return true;
            }
        }
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] != src.ip_ary[i]) {
                return true;
            }
        }
    }

    return false;
}

bool TAG_IP_ADDR_ARY::operator == (const TAG_IP_ADDR_ARY& src) const {
    int i = 0;

    if (!this->is_valid() || !src.is_valid()) {
        return false;
    }

    if (this->is_ipv4() && src.is_ipv4()) {
        // 按照ipv4比对
        for (i = 12; i <= 15; i++) {
            if (this->ip_ary[i] != src.ip_ary[i]) {
                return false;
            }
        }

        return true;
    } else {
        // 按照ipv6比对
        for (i = 0; i <= 15; i++) {
            if (this->ip_ary[i] != src.ip_ary[i]) {
                return false;
            }
        }

        return true;
    }

    return false;
}

// '0'~'9' 'a'~'f' 'A'~'F' to 0~15
uchar TAG_IP_ADDR_ARY::get_ascii_char_value(char c_in)
{
    if ((c_in >= '0') && (c_in <= '9')) {
        return (uchar)(c_in - '0');
    } else if ((c_in >= 'a') && (c_in <= 'f')) {
        return (uchar)(c_in - 'a' + 10);
    } else if ((c_in >= 'A') && (c_in <= 'F')) {
        return (uchar)(c_in - 'A' + 10);
    } else {
        return 0;
    }
}

猜你喜欢

转载自blog.csdn.net/LostSpeed/article/details/82114421
今日推荐