множественное определение в заголовочном файле

Как указано в в этом учебнике :

В Electron у нас есть несколько способов связи между основными процессами и процессами рендеринга, такими как ipcRenderer и ipcMain модули для отправка сообщений и удаленный модуль для связи в стиле RPC.

blockquote>

Итак, вы можете следовать примеру в https://github.com/electron/electron-api-demos . У вас должен быть файл js для каждого html. require

Код в renderer.js :

const ipc = require('electron').ipcRenderer

const asyncMsgBtn = document.getElementById('async-msg')

asyncMsgBtn.addEventListener('click', function () {
  ipc.send('asynchronous-message', 'ping')
})

ipc.on('asynchronous-reply', function (event, arg) {
  const message = `Asynchronous message reply: ${arg}`
  document.getElementById('async-reply').innerHTML = message
})

Код в ipc.html :


30
задан Keith Pinson 11 February 2013 в 19:19
поделиться

3 ответа

Проблема в том, что следующий фрагмент кода является определением, а не объявлением:

std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
   return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
}

Вы можете либо пометить функцию выше, либо сделать ее «встроенной», чтобы множественный перевод единицы могут определять его:

inline std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
   return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
}

Или вы можете просто переместить исходное определение функции в исходный файл "complex.cpp".

Компилятор не жалуется на «real ()», потому что он неявно встроен (любая функция-член, тело которой указано в объявлении класса, интерпретируется так, как если бы она была объявлена ​​«встроенной»). Защита препроцессора предотвращает включение вашего заголовка более одного раза из одной единицы перевода ("* .cpp" исходный файл "). Однако обе единицы перевода видят один и тот же файл заголовка. Как правило, компилятор компилирует" main.cpp "в "main.o" (включая любые определения, данные в заголовках, включенных в "main.cpp"), и компилятор отдельно компилирует "complex.cpp" в "complex.o" (включая любые определения, данные в заголовках, включенных в "complex .cpp "). Затем компоновщик объединяет" main.o "и" complex.o "в один двоичный файл; именно в этот момент компоновщик находит два определения для функции с тем же именем. указать, что компоновщик пытается разрешить внешние ссылки (например, «main.o» относится к «Complex :: Complex», но не имеет определения для этой функции ...компоновщик находит определение из "complex.o" и разрешает эту ссылку).

49
ответ дан 27 November 2019 в 22:00
поделиться

И есть ли другое решение, как использование ключевого слова inline ?

Да, есть. Помимо формы определения метода внутри файла реализации complex.cpp , как упоминалось другими, вы также можете поместить определение в безымянное пространство имен.

namespace {
    std::ostream& operator<<(std::ostream& o, const Complex& Cplx) {
        return o << Cplx.m_Real << " i" << Cplx.m_Imaginary;
    }
}

На практике это создаст уникальное пространство имен для каждой единицы компиляции. Таким образом вы предотвратите конфликт имен. Однако имена по-прежнему экспортируются из модуля компиляции, но бесполезны (поскольку имена неизвестны).

Помещение определения в файл реализации часто оказывается лучшим решением. Однако для шаблонов классов вы не можете этого сделать, поскольку компиляторы C ++ не поддерживают создание экземпляров шаблонов в модуле компиляции, отличном от того, в котором они были определены. В этом случае вы должны использовать либо ] встроенный или безымянное пространство имен.

12
ответ дан 27 November 2019 в 22:00
поделиться

Перенести реализацию в complex.cpp

Прямо сейчас после включения этого файла реализация компилируется в каждый файл. Позже во время связывания возникает очевидный конфликт из-за дублирования реализаций.

:: real () не сообщается, потому что он неявно встроен (реализация внутри определения класса)

5
ответ дан 27 November 2019 в 22:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: