Подтвердить что ты не робот

Почему функции члена класса встроены?

Я думаю, что мой вопрос был задан здесь раньше, я прочитал их, но все еще немного смущен и поэтому прошу дать понять.

The C++ standard says all member functions defined inside class definition are inline

Я также слышал, что компилятор может игнорировать встроенную функцию. Будет ли это верным в вышеуказанном случае или оно будет всегда включено, если определено внутри определения класса?

Кроме того, в чем причина этой конструкции, делая все функции определенными внутри определения класса inline? И какая вложенность связана с исходными и заголовочными файлами?

Обновление:. Нужно всегда определять свои функции вне класса, если не быть встроенным, правильно?

Обновление 2 от JohnB: Две функции, объявленные внутри определения класса, никогда не могут звонить друг другу, так как они должны были бы содержать все тело другой функции. Что произойдет в этом случае? (Уже ответил Эмилио Гаравалья)

4b9b3361

Ответ 1

Замешательство возникает из-за того, что inline имеет два эффекта:

  • Он сообщает компилятору, что код функции может быть расширен, где функция вызывается, а не эффективно вызываться.
  • Он сообщает компилятору, что определение функции может быть повторено.

Точка 1. "архаична" в том смысле, что компилятор действительно может делать то, что ему нравится, для оптимизации кода. Он всегда будет "встроенным" машинным кодом, если он может и удобен в работе, и он никогда не сделает этого, если не сможет.

Точка 2. является фактическим значением термина: если вы define (укажите тело) функцию в заголовке, так как заголовок может быть включен в большее количество источников, вы должны сообщить компилятору сообщить компоновщику о определение дублируется, так что их можно объединить.

Теперь, по спецификации языка, свободные функции (не определенные в телах классов) по умолчанию не определены как встроенные, поэтому определяют в заголовке такую ​​вещь, как

void myfunc()
{}

если заголовок включен в большее количество источников, а затем связан с одним и тем же выходом, компоновщик сообщит об ошибке множественного определения, поэтому необходимо определить его как

inline void fn()
{}

Для членов класса значение по умолчанию противоположно: если вы просто объявите их, они не будут включены. Если вы их определите, они будут встроены.

Итак, заголовок должен выглядеть как

//header file

class myclass
{
public:
    void fn1()
    {} //defined into the class, so inlined by default

    void fn2();
};

inline void myclass::fn2()
{} //defined outside the class, so explicit inline is needed

И если определение myclass::fn2() переходит в правильный источник, оно должно потерять ключевое слово inline.

Ответ 2

Ключевое слово inline имеет значение для функции 2:

  • Замена кода: везде, где вызывается функция inline, не генерировать вызов функции для нее, а просто размещать содержимое функции на месте его вызова (это нечто похожее на макрос замена, но тип сейфа).
  • Одно правило определения: не генерировать множественное определение для функции inline, генерировать только одно общее определение для всех (исключение: static)

Первая терминология ( "Замена кода" ) - это просто запрос для компилятора. которые могут быть проигнорированы, поскольку компилятор лучше судить о том, следует ли отправлять текст или вызов функции. (например, функции virtual или рекурсивные функции не могут быть встроены).

Вторая терминология ( "Одно правило определения" ) гарантирована, которая должна выполняться любым соответствующим компилятором. Это будет генерировать только 1 определение для всех единиц перевода. Этот способ облегчает работу кодера, так как для более мелкой функции нельзя поместить свое определение в файл .cpp (например, getters, seters).
Более того, для функции template, которая является только конструкцией заголовка, этот эффект является обязательным. Таким образом, template функции inline по умолчанию.

Примеры:

class A {
public:
  void setMember (int i) { m_i = i; }
};

В этом примере в основном компилятору хватит обеих терминов

class A {
  inline virtual ~A () = 0;
};
A::~A() {}

Здесь компилятору может быть достаточно 2-го требования.

Ответ 3

Единственная причина, по которой функция метода встроена, заключается в том, что вы определяете ее в заголовке.

Если вы определяете функцию метода в заголовке, и вы не ставите ключевое слово inline, и вы включаете заголовок в несколько заголовков или исходных файлов, вы получите множественное определение метода.

С++ 11 standard в 9.3/2 Функции членов [class.mfct] сообщает:

Функция члена может быть определена (8.4) в определении класса, и в этом случае она является встроенной функцией-членом (7.1.2)...

Ответ 4

Компилятор может игнорировать вложение, если задано ключевым словом inline. Если реализация метода присутствует внутри определения класса, это другое дело и не может быть проигнорировано. (ну, может, но это делает компилятор несоответствующим)

Причина создания - я предполагаю, что механизм был необходим, когда вы действительно можете заставить компилятор фактически встроить ваши функции, поскольку ключевое слово inline не предусматривает его. Но в целом определение встроенного метода выполняется только в таких случаях, как методы getter и setter, или некоторые тривиальные 2-лайнеры. И шаблоны, но это другая проблема.

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

РЕДАКТИРОВАТЬ: На боковой ноте абзац, который указывает op, равен 7.1.2.3:

Функция, определенная в определении класса, является встроенной функцией [...].

EDIT2:

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

Таким образом, функция может быть встроена, но не имеет своего тела, вставленного вместо вызова.

Ответ 5

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

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

Итак, короче говоря, он не обрабатывается ничем не отличающимся от функций, которые явно объявлены inline.

Ответ 6

две вещи, о которых вы говорите, - это разные аспекты, и их нельзя путать.

1) Стандарт С++ говорит, что все функции-члены, определенные внутри определения класса, являются встроенными

2) Я также слышал, что компилятор может игнорировать вложение функции

1) - это когда вы определяете функции-члены внутри самого объявления класса. т.е.: в файлах заголовков. для этого вам не нужно предоставлять какое-либо ключевое слово (например: inline)

2) Вы можете указать функцию как встроенную, явно используя ключевое слово inline. это на самом деле запрос компилятору. компилятор может или не может сделать функцию встроенной в соответствии с некоторыми правилами оптимизации.