Как реализовать одно правило определения

Этот пост ссылается на правило единого определения.

Википедия плохо объясняет, как это реализовать

Где я могу найти хорошие источники о рекомендациях, которым следует следовать в C ++ .NET?


person Eric    schedule 19.12.2008    source источник
comment
Что вы имеете в виду под этим? Как не нарушить правила?   -  person jalf    schedule 19.12.2008


Ответы (2)


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

file1.cpp

int square(int x); // this is a declaration
extern int someVariable; // this is a declration

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file2.cpp

int square(int x); // this is a declaration

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}       

Когда компилятор начинает компилировать объектный код, он читает объявления и помещает их в свою таблицу. В конце компиляции file1.cpp получится что-то вроде этого:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    12 34 56 78 aa XX XX XX XX ab cd
definition:
    square: starts at address 0

Это предполагает, что функция компилируется для этих конкретных инструкций по сборке. Во время компоновщика XX XX XX XX будет заменен адресом someVariable.

File2 заканчивается примерно так:

declarations:
    square (XX): function that returns int, and takes a single int as parameter [4 bytes]
    someVariable (YY): integer [4 bytes]
data:
    00 00 00 00 12 34 56 78 12 34 56 YY YY YY YY 23 21
definitions:
    someVariable: starts at address 0
    main: starts at address 4

И в этом случае YY будет заменен адресом квадрата.

Вот где в игру вступает линкер. Задача компоновщика - просмотреть список и построить таблицу, в которой все находится в адресном пространстве программы во время компиляции. Однако возникает проблема, если два объектных файла имеют одно и то же определение переменной при попытке связи. Если бы в приведенном выше примере было два определения someVariable, то он не знал бы, чем заменить YY. Точно так же, если определения нет, вы получите ужасные ошибки компоновщика.

«Решение» этого правила состоит в том, чтобы разделить ваш файл таким образом, чтобы у вас были определения только в файлах .cpp и объявления вещей в ваших файлах .h, поэтому приведенный выше пример будет выглядеть следующим образом:

file1.cpp

#include "file2.h"

void square(int x)  // this is a definition
{
    return x * someVariable;
}

file1.h

int square(int x); // this is a declaration

file2.cpp

#include "file1.h"

int someVariable; // this is a definition    
void main()
{
    someVariable = 12;
    someVariable = square(4);
}

file2.h

extern int someVariable;

Обратите внимание, что это невероятно простой пример, и что он на самом деле неприменим в .NET, поскольку нет концепции различия между объявлением и определением.

person FryGuy    schedule 19.12.2008
comment
Это наиболее сложное описание очень простой концепции, которое я видел за долгое время. - person Martin York; 19.12.2008

Самый простой способ выполнить одно правило определения - поместить определение в файл .cpp вместо заголовка.

Иногда люди помещают определения в заголовки, используя макросы и / или условные выражения препроцессора, чтобы объект или функция были определены только в одной единице компиляции. Но обычно проще (и, конечно, более понятно) просто поместить определение в файл .cpp.

person Michael Burr    schedule 19.12.2008