Переопределение и перегрузка в C++

31
задан Daniel Daranas 29 October 2013 в 09:44
поделиться

6 ответов

Перегрузка обычно средства, что у Вас есть две или больше функции в том же объеме, имеющем то же имя. Функция, что лучшие соответствия аргументы, когда вызов выполняют победы и называют. Важный для замечания, в противоположность вызыванию виртуальной функции, то, что функция, которой это называют, выбрана во время компиляции. Все это зависит от статического типа аргумента. Если у Вас есть перегрузка для B и один для D, и аргументом является ссылка на B, но он действительно указывает на D объект, то перегрузка для B выбрана в C++. Это звонило статическая отправка в противоположность [1 113] динамическая отправка . Вы перегружаетесь, если Вы хотите сделать то же как другую функцию, имеющую то же имя, но Вы хотите сделать это для другого типа аргумента. Пример:

void print(Foo const& f) {
    // print a foo
}

void print(Bar const& bar) {
    // print a bar
}

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

void print(Foo & f, PrintAttributes b) { 
    /* ... */ 
}

void print(Foo & f, std::string const& header, bool printBold) {
    print(f, PrintAttributes(header, printBold));
}

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

Переопределение является чем-то совершенно другим. Это не конкурирует с перегрузкой. Это означает, что, если у Вас есть виртуальная функция в базовом классе, можно записать функцию с той же подписью в производном классе. Функция в производном классе переопределения функция основы. Образец:

struct base {
    virtual void print() { cout << "base!"; }
}

struct derived: base {
    virtual void print() { cout << "derived!"; }
}

Теперь, если Вы имеете объект и звоните print функция членства, функция печати полученного всегда вызывается, потому что это переопределяет тот основы. Если бы функция print не была виртуальной, то функция в полученном не переопределила бы основную функцию, но была бы просто скрываться она. Переопределение может быть полезным, если у Вас есть функция, которая принимает базовый класс и всех, кого это получено из него:

void doit(base &b) {
    // and sometimes, we want to print it
    b.print();
}

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

69
ответ дан 27 November 2019 в 21:24
поделиться

Примером из учебника является класс Животное с методом, говорят (). Переопределения подкласса Собаки говорят () для "лаяния", в то время как переопределения подкласса CAT говорят () для "мяукания".

2
ответ дан 27 November 2019 в 21:24
поделиться

Вы более чем загрузка функции по трем причинам:

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

    void Log(std::string msg); // logs a message to standard out
    void Log(std::string msg, std::ofstream); // logs a message to a file
    
  2. Для обеспечения два (или больше) способы выполнить то же действие. Изобретенный пример:

    void Plot(Point pt); // plots a point at (pt.x, pt.y)
    void Plot(int x, int y); // plots a point at (x, y)
    
  3. Для обеспечения способности выполнить эквивалентное действие, учитывая два (или больше) различные входные типы. Изобретенный пример:

    wchar_t      ToUnicode(char c);
    std::wstring ToUnicode(std::string s);
    

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

<час>

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

19
ответ дан 27 November 2019 в 21:24
поделиться

Люди уже определили и перегрузку и переопределение, таким образом, я не уточню.

ASAFE, который спрашивают:

единственное преимущество [к перегрузке] является Вами, не имеют, думают на несколько имен к функциям?

1. Вы не должны думать на несколько имен

, И это уже - могущественное преимущество, не так ли?

Позволяют нам соответствовать известным API-функциям C и их вымышленным вариантам C++:

/* C */
double fabs(double d) ;
int abs(int i) ;

// C++ fictional variants
long double abs(long double d) ;
double abs(double d) ;
float abs(float f) ;
long abs(long i) ;
int abs(int i) ;

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

И все, что он хотел, должно было иметь абсолютное значение некоторой числовой переменной...

Одно действие означает одно и только одно имя функции.

Примечание, что Вы не ограничены для изменения типа одного параметра. Что-либо может измениться, пока это имеет смысл.

2. Для операторов это обязательно

, Давайте посмотрим операторов:

// C++
Integer operator + (const Integer & lhs, const Integer & rhs) ;
Real operator + (const Real & lhs, const Real & rhs) ;
Matrix operator + (const Matrix & lhs, const Matrix & rhs) ;
Complex operator + (const Complex & lhs, const Complex & rhs) ;

void doSomething()
{
   Integer i0 = 5, i1 = 10 ;
   Integer i2 = i0 + i1 ; // i2 == 15

   Real r0 = 5.5, r1 = 10.3 ;
   Real r2 = r0 + r1 ; // r2 = 15.8

   Matrix m0(1, 2, 3, 4), m1(10, 20, 30, 40) ;
   Matrix m2 = m0 + m1 ; // m2 == (11, 22, 33, 44)

   Complex c0(1, 5), c1(10, 50) ;
   Complex c2 = c0 + c1 ; // c2 == (11, 55)
}

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

Примечание, что C имеет неявный оператор, перегружающийся для встроенных типов (включая составной тип C99):

/* C */
void doSomething(void)
{
   char c = 32 ;
   short s = 54 ;
   c + s ; /* == C++ operator + (char, short) */
   c + c ; /* == C++ operator + (char, char) */
}

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

3. Для объектов это обязательно

, Давайте посмотрим использование объектные основные методы: Его конструкторы:

class MyString
{
   public :
      MyString(char character) ;
      MyString(int number) ;
      MyString(const char * c_style_string) ;
      MyString(const MyString * mySring) ;
      // etc.
} ;

Некоторые могли рассмотреть это как перегрузка функции, но на самом деле, это более подобно перегрузке оператора:

void doSomething()
{
   MyString a('h') ;                  // a == "h" ;
   MyString b(25) ;                   // b == "25" ;
   MyString c("Hello World") ;        // c == "Hello World" ;
   MyString d(c) ;                    // d == "Hello World" ;
}

Заключение: Перегрузка прохладна

В C, когда Вы даете название функции, параметры являются implicitely частью подписи в вызове. Если у Вас есть "двойной fabs (удвойте d)", затем, в то время как подпись fabs для компилятора является неукрашенным "fabs", это означает, что необходимо знать, что это берет, только удваивается.

В C++, название функции не означает, что ее подпись вызывается. Его подпись в вызове является его именем и его параметрами. Таким образом, если Вы запишете брюшной пресс (-24), то компилятор будет знать, какую перегрузку брюшного пресса он должен назвать, и Вы, при записи этого, найдите это более естественным: Вы хотите абсолютное значение-24.

Так или иначе, любой, кто кодировал несколько на любом языке с операторами уже, использует перегрузку, быть им C или Основные числовые операторы, конкатенация строк Java, делегаты C#, и т.д. Почему? , потому что это более естественно .

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

3
ответ дан 27 November 2019 в 21:24
поделиться

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

Перегрузка не необходима, но она уверенный делает жизнь легче или более читаемой иногда. Возможно это может сделать это хуже, но именно тогда это не должно использоваться. Например, у Вас может быть две функции, которые выполняют ту же операцию, но действие на различных видах вещей. Например Divide(float, float) должно отличаться от Divide(int, int), но они - в основном та же операция. Вы не помнили бы одного имени метода, "Разделились" бы, чем имели бы для запоминания "DivideFloat", "DivideInt", "DivideIntByFloat", и так далее?

4
ответ дан 27 November 2019 в 21:24
поделиться

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

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

1
ответ дан 27 November 2019 в 21:24
поделиться
Другие вопросы по тегам:

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