重载超类中的运算符,但子类声明它';它已经定义好了 我正在学习C++,我对继承和操作符重载的工作有点不清楚,所以我很可能在这里做一些傻事。

重载超类中的运算符,但子类声明它';它已经定义好了 我正在学习C++,我对继承和操作符重载的工作有点不清楚,所以我很可能在这里做一些傻事。,c++,visual-c++,C++,Visual C++,我有一个基类,它定义了一些表示度量单位的非常基本的操作: #pragma once class UnitOfMeasure { public: UnitOfMeasure(void) : mAmount(0) {} UnitOfMeasure(double amount) : mAmount(amount) { } ~UnitOfMeasure() {} void SetAmount(double amount) { mAmount = amount; }

我有一个基类,它定义了一些表示度量单位的非常基本的操作:

#pragma once
class UnitOfMeasure
{
public:
    UnitOfMeasure(void) : mAmount(0) {}
    UnitOfMeasure(double amount) : mAmount(amount) { }
    ~UnitOfMeasure() {}

    void SetAmount(double amount) { mAmount = amount; }

    UnitOfMeasure& operator+=(const UnitOfMeasure& rhs)
    {
        mAmount += rhs.mAmount;
        return *this;
    }

    friend bool operator==(const UnitOfMeasure&, const UnitOfMeasure&);

protected:
    double mAmount;
};

bool operator==(const UnitOfMeasure& lhs, const UnitOfMeasure &rhs)
{
    return rhs.mAmount == lhs.mAmount;
}
然后子类实现如下特定转换:

#pragma once
#include "UnitOfMeasure.h"

class Temperature : public UnitOfMeasure
{
public:
    enum TemperatureUnit { CELSIUS, FAHRENHEIT };
    Temperature(void) { }
    Temperature(double amount, TemperatureUnit units=CELSIUS) { SetAmount(amount, units); }
    ~Temperature(void) {};
    void SetAmount(double amount, TemperatureUnit units=CELSIUS)
    {
        switch(units)
        {
            case CELSIUS: { mAmount = amount; break; }
            case FAHRENHEIT: { mAmount = (amount - 32) / 1.8; break; }
        }
    }
    double Fahrenheit() { return 32 + (mAmount * 1.8); }
    double Celsius() { return mAmount; };
};
在我的示例程序中,我将温度实例存储在一个列表中,这就是事情开始变得奇怪的地方。当所有代码都包含在.h文件中时,一切正常。我可以成功编译和运行。然而,当我将温度的代码分解成一个单独的.cpp文件时,编译器会抱怨。我收到这些信息:

1>  Temperature.cpp
1>Temperature.obj : error LNK2005: "bool __cdecl operator==(class UnitOfMeasure const &,class UnitOfMeasure const &)" (??8@YA_NABVUnitOfMeasure@@0@Z) already defined in BadComparison.obj
1> BadComparison.exe : fatal error LNK1169: one or more multiply defined symbols found
(我正在使用Visual Studio 2012)

编译器是否为我的温度类创建单独的==运算符


谢谢

您应该将运算符声明为
内联
,以避免其定义成为包含相应头文件的多个翻译单元的一部分:

    inline bool operator==(const UnitOfMeasure& lhs, const UnitOfMeasure &rhs)
//  ^^^^^^
    {
        return rhs.mAmount == lhs.mAmount;
    }

在这种情况下,链接器最终会抱怨同一个函数在程序中被多次定义,这违反了。

您所做的事情将无法按您所希望的方式工作。也就是说,你的代码认为100塞尔修斯等于100费伦海等于100英寸(
boost::units
它的可能副本似乎起到了作用,谢谢。但我仍然不明白为什么编译器会认为该运算符有多个定义。没有内联,每个包含头的.cpp文件都有效地重新定义了该函数。@Alex:编译器会处理每个翻译单位(即
.cpp
文件)另外,当处理一个翻译单元时,它不会记得在编译其他翻译单元时处理了什么。如果
a.cpp
b.cpp
都包含
c.h
,并且
c.h
包含函数定义,则该定义将在
a.cpp
生成的目标代码中编译(说
a.o
)和从
b.cpp
生成的目标代码中(说
b.o
)。然后,当链接器将
a.o
b.o
合并以获得您的
.exe
时,它将找到一个多次定义的函数,并发出一个错误。@Alex:
inline
关键字防止这种情况发生,并允许您将函数的定义放在标题中(注意,常规的编程实践是在
.cpp
文件中有函数定义,除非它们是模板或类模板的成员函数)。是的,这很有帮助。谢谢。我想我现在明白了。我认为#pragma一次(或#ifndef/#define/#end)是防止这类事情发生的保护措施,但由于链接步骤,情况显然不是这样。