Что означает переопределение?

Верно ли, что переопределение означает, что мы пытаемся определить сущность, которая уже определена. Этот вопрос появляется из следующего примера кода:

int a=5;

int main()
{
    int a=3;//redefinition? I think no, because `int a` denote an entity different from the global "a"
}

и еще один пример:

int foo(){ return 1; }

int main()
{
    int foo();
    int a=foo();//Now a is 1
}

Мы не можем определить только что объявленную функцию foo() внутри тела функции main(), но если мы сможем, будет ли это переопределением?


person Community    schedule 15.05.2014    source источник
comment
@Deduplicator Я не понимаю, что означает переопределение. Я просто думаю об этом. Я пытаюсь понять...   -  person    schedule 15.05.2014
comment
Обратите внимание, что в C существует разница между объявлением и определением.   -  person Hot Licks    schedule 15.05.2014


Ответы (5)


Локальные переменные могут затмевать глобальные, для этого и предназначен оператор разрешения области видимости ::.

#include <iostream>
using namespace std;

int a=5;

int main()
{
    int a=3;

    cout << a; // 3
    cout << ::a; // 5
}

поэтому здесь нет проблем с ODR.

Что касается второго примера, объявления функции внутри другой функции (если его не смущает наиболее раздражающий анализ), я рекомендую этот вопрос: Есть ли смысл в объявлениях функций внутри функций?

И: нет, вы не можете переопределить свою функцию внутри main(). Вы можете повторно объявить ее (даже с другими параметрами, тем самым объявив новую функцию), но это не означает, что вы можете определить ее так.

На вики-странице есть отличный отрывок, который я рекомендую прочитать:

Короче говоря, ODR утверждает, что:

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

  • Во всей программе объект или не встроенная функция не может иметь более одного определения; если объект или функция используются, они должны иметь ровно одно определение. Вы можете объявить объект или функцию, которые никогда не используются, и в этом случае вам не нужно указывать определение. Ни в коем случае не может быть более одного определения.

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

Некоторые нарушения ODR должны диагностироваться компилятором. Другие нарушения, особенно те, которые охватывают единицы перевода, диагностировать не требуется.1

person Marco A.    schedule 15.05.2014
comment
Вы имели в виду, что переопределение — это когда мы пытаемся переопределить уже определенную сущность? - person ; 15.05.2014
comment
ODR = одно правило DEFINITION, это означает, что вы не можете переопределять вещи, иначе вы получите повторяющиеся символы. Так да. - person Marco A.; 15.05.2014
comment
Большое спасибо. Я пытался понять эту концепцию ни один день. Теперь я понял. :) - person ; 15.05.2014

Нет, при работе с переопределением важно помнить ОБЛАСТЬ ПРИМЕНЕНИЯ. Это применимо только для двух переменных с одинаковым именем, которые определены в ОДНОЙ ОБЛАСТИ ОБЛАСТИ

В примере 1 второй параметр a имеет значение LOCAL SCOPE и является локальным для функции. Следовательно, это a, который просматривается и на который ссылаются до тех пор, пока вы не выйдете из тела функции.

person Seyon    schedule 15.05.2014
comment
Как раз наоборот. Переопределение не имеет ничего общего с областями действия. Области имеют дело с объявлениями имен, определения имеют дело с сущностями, обозначенными именами. - person ach; 15.05.2014

int a = foo(); или int a = 3; внутри main() — это новая переменная, которая также называется a.

Переопределение — это попытка переопределить ту же переменную, например:

int a = 5;
int a = 6;

Также

int foo();

не является определением. Это декларация. Определение функции включает { }.

person M.M    schedule 15.05.2014
comment
Это не объясняет моего непонимания. Пожалуйста, посмотрите мой первый пример, где int переопределен в main(). - person ; 15.05.2014

Переопределение - это то, что приводит к ошибке времени компиляции. Например:

int a;
bool a;

or

void f();
int f;

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

int a = 5;
{
  int a = 6; //because of { } internal a is in other scope and can be defined without error
  int b = a; //b == 6
}
int b = a; //b == 5

В последнем случае у вас есть два разных "а", каждый в своей области программы. В одном месте программы, если вы используете такое имя, как «а», за этим именем стоит только одна сущность. Если компилятор не может найти наилучшее соответствие для «a» между различными вариантами, вы получите переопределение и ошибку.

person Arsenii Fomin    schedule 15.05.2014
comment
Ваши примеры не относятся к переопределению. Это те, которые связаны с несовместимым повторным объявлением имен. В частности, ни в каком контексте конструкция void f(); не может быть определением, это всегда просто объявление. - person ach; 15.05.2014
comment
Ты прав. Однако вопрос был не совсем о переопределении, а о непонимании области имен. - person Arsenii Fomin; 16.05.2014

Первый не является переопределением из-за разных областей видимости, как вы думали.

Второй — это переобъявление, но можно переобъявить что-то любое количество раз, хотя шутка устаревает при повторении.

Если вы разрешаете определение функций внутри функций, вы можете написать всю семантику, потому что ее еще нет (кроме лямбда-выражений).
Для тех, кто это сделал, посмотрите на компилятор GCC C, "вложенные функции" и «выражения оператора».

В любом случае переопределение было бы ошибкой из-за правила одного определения.

person Deduplicator    schedule 15.05.2014