Где объявить перегрузку оператора структуры - PullRequest
1 голос
/ 03 февраля 2020

Я новичок ie в C ++ (я пришел с C#).

У меня есть эта структура внутри пространства имен:

#pragma once

namespace utils { 

    struct astTime
    {
        int hour;
        int min;
        double secs;
    };

    double round(double number, int decPlace);
}

У меня также есть исходный файл где я реализовал round функцию.

Чтобы использовать эту структуру в Boost Test, я определил эти два оператора в файле Boost Test (. cpp):

namespace utils {
    bool operator ==(utils::astTime const &left, utils::astTime const &right)
    {
        return(
            left.secs == right.secs
            && left.min == right.min
            && left.hour == right.hour);
    }

    std::ostream& operator<<(std::ostream& os, const utils::astTime& dt)
    {
        os << dt.hour << "h " << dt.min << "m " << dt.secs << "s" << std::endl;

        return os;
    }
}

Где я должен объявить эти два оператора (и как)?

Я переместил его в файл заголовка (потому что Я НЕ ЗНАЮ, ГДЕ ОБЪЯВЛЯТЬ ЭТО ), удаляя их из исходного файла буст-теста, таким образом:

#pragma once
#include <iostream>

namespace utils { 

    struct astTime
    {
        int hour;
        int min;
        double secs;
    };

    bool operator ==(utils::astTime const &left, utils::astTime const &right)
    {
        return(
            left.secs == right.secs
            && left.min == right.min
            && left.hour == right.hour);
    }

    std::ostream& operator<<(std::ostream& os, const utils::astTime& dt)
    {
        os << dt.hour << "h " << dt.min << "m " << dt.secs << "s" << std::endl;

        return os;
    }

    double round(double number, int decPlace);
}

И я получаю следующую ошибку:

предупреждение LNK4006: "class std :: basic_ostream> & __cdecl utils :: оператор << (класс std :: basic_ostream> &, struct utils :: astTime const &) "(?? 6utils @@ YAAAV? $basic_ostream@DU?$char_traits@D@std@@@std@@AAV12@ABUastTime@0@@Z) уже определен в Utils.obj; второе определение игнорируется

Ответы [ 2 ]

0 голосов
/ 03 февраля 2020

Обычно при написании класса вы объявляете все операторы в том же заголовке и пространстве имен, что и класс. Это позволяет всем пользователям класса иметь одинаковый набор операторов, доступных для объектов класса. Из этого правила могут быть исключения (например, чтобы иметь операторы ввода-вывода в отдельном заголовке для сокращения времени компиляции), но общее правило остается в силе. Заголовок или нет это отдельный вопрос. Как правило, вы предоставляете определения в заголовках, когда они легковесны и их желательно встроить в сайт вызова. Кроме того, вы обычно предоставляете определения в заголовке, если операторы являются шаблонами.

Ошибка компоновщика в том, что ваш оператор definition находится в заголовке, который включен в несколько единиц перевода (. cpp файлов). Фактически это означает, что определение дублируется в нескольких единицах перевода, составляющих программу, что нарушает ODR . Чтобы исправить это, вы можете пометить оператор inline, что позволит компилятору использовать только одно из нескольких определений в конечной программе (в случае, если оно не встроено на каждом сайте вызова).

0 голосов
/ 03 февраля 2020

Вы смешиваете объявление и определение в своем коде. Поместите определения в файл реализации (*.cpp). Поместите объявления в заголовок рядом с вашим объявлением round.

В качестве альтернативы, вы могли бы поместить определения в заголовок и объявить их inline (и это обычно для коротких функций, таких как пользовательские операторы). Спецификатор inline для функций не позволяет функциям нарушать правило One Definition при включении несколькими единицами перевода.

...