C++中的覆盖和重载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/429125/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 15:18:12  来源:igfitidea点击:

Override and overload in C++

c++overridingoverloading

提问by Hai

Yes, I do understand the difference between them. What I want to know is: why OVERRIDE a method? What is the good in doing it? In case of overload: the only advantage is you haven't to think in different names to functions?

是的,我确实理解它们之间的区别。我想知道的是:为什么要覆盖一个方法?这样做有什么好处?在过载的情况下:唯一的好处是您不必考虑函数的不同名称?

回答by Johannes Schaub - litb

Overloadinggenerally means that you have two or more functions in the same scope having the same name. The function that better matches the arguments when a call is made wins and is called. Important to note, as opposed to calling a virtual function, is that the function that's called is selected at compile time. It all depends on the static type of the argument. If you have an overload for Band one for D, and the argument is a reference to B, but it really points to a Dobject, then the overload for Bis chosen in C++. That's called static dispatchas opposed to dynamic dispatch. You overload if you want to do the same as another function having the same name, but you want to do that for another argument type. Example:

重载通常意味着您在同一作用域中有两个或多个具有相同名称的函数。调用时与参数更好匹配的函数获胜并被调用。需要注意的是,与调用虚函数相反,被调用的函数是在编译时选择的。这一切都取决于参数的静态类型。如果你有一个 forB和一个 for的重载D,并且参数是对 的引用B,但它确实指向一个D对象,那么B在 C++ 中选择了重载 for 。这称为静态调度而不是动态调度. 如果您想对另一个具有相同名称的函数执行相同的操作,则可以重载,但是您想对另一个参数类型执行此操作。例子:

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

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

they both print their argument, so they are overloaded. But the first prints a foo, and the second prints a bar. If you have two functions that do different things, it's considered bad style when they have the same name, because that can lead to confusion about what will happen actually when calling the functions. Another usecase for overloading is when you have additional parameters for functions, but they just forward control to other functions:

他们都打印了他们的论点,所以他们被重载了。但是第一个打印一个 foo,第二个打印一个 bar。如果你有两个做不同事情的函数,当它们具有相同的名称时被认为是糟糕的风格,因为这会导致对调用函数时实际发生的事情的混淆。重载的另一个用例是当您有函数的附加参数时,但它们只是将控制权转发给其他函数:

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

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

That can be convenient for the caller, if the options that the overloads take are often used.

如果经常使用重载所采用的选项,这对调用者来说会很方便。

Overridingis something completely different. It doesn't compete with overloading. It means that if you have a virtual function in a base class, you can write a function with the same signature in the derived class. The function in the derived class overridesthe function of the base. Sample:

覆盖是完全不同的东西。它不与重载竞争。这意味着如果基类中有虚函数,则可以在派生类中编写具有相同签名的函数。派生类中的函数覆盖了基类的函数。样本:

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

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

Now, if you have an object and call the printmember function, the print function of the derived is always called, because it overrides the one of the base. If the function printwasn't virtual, then the function in the derived wouldn't override the base function, but would merely hideit. Overriding can be useful if you have a function that accepts a base class, and every one that's derived from it:

现在,如果您有一个对象并调用print成员函数,则始终调用派生函数的打印函数,因为它覆盖了基函数。如果函数print不是虚函数,则派生函数中的函数不会覆盖基函数,而只会隐藏它。如果您有一个接受基类的函数以及从它派生的每个函数,则覆盖可能很有用:

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

Now, even though at compile time the compiler only knows that b is at least base, print of the derived class will be called. That's the point of virtual functions. Without them, the print function of the base would be called, and the one in the derived class wouldn't override it.

现在,即使在编译时编译器只知道 b 至少是基数,派生类的打印也会被调用。这就是虚函数的意义所在。没有它们,将调用基类的打印函数,派生类中的函数不会覆盖它。

回答by subhash kumar singh

This will add some more clarity to thoughts.enter image description here

这将使想法更加清晰。enter image description here

回答by P Daddy

You overloadfunctions for three reasons:

超载功能的三个原因:

  1. To provide two (or more) functions that perform similar, closely related things, differentiated by the types and/or number of arguments it accepts. Contrived example:

    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. To provide two (or more) ways to perform the same action. Contrived example:

    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. To provide the ability to perform an equivalent action given two (or more) different input types. Contrived example:

    wchar_t      ToUnicode(char c);
    std::wstring ToUnicode(std::string s);
    
  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);
    

In somecases it's worth arguing that a function of a different name is a better choice than an overloaded function. In the case of constructors, overloading is the only choice.

某些情况下,值得争论的是,不同名称的函数比重载函数更好。对于构造函数,重载是唯一的选择。



Overridinga function is entirely different, and serves an entirely different purpose. Function overriding is how polymorphism works in C++. You override a function to change the behavior of that function in a derived class. In this way, a base class provides interface, and the derived class provides implementation.

的功能是完全不同的,并且用于完全不同的目的。函数覆盖是多态在 C++ 中的工作方式。您可以覆盖一个函数以更改该函数在派生类中的行为。这样,基类提供接口,派生类提供实现。

回答by lc.

Override is useful when you inherit from a base class and wish to extend or modify its functionality. Even when the object is cast as the base class, it calls your overridden function, not the base one.

当您从基类继承并希望扩展或修改其功能时,覆盖很有用。即使对象被强制转换为基类,它也会调用您的重写函数,而不是基类。

Overloading is not necessary, but it sure makes life easier or more readable sometimes. Arguably it can make it worse, but that's when it should not be used. For example, you can have two functions that perform the same operation, but act on different kinds of things. For example Divide(float, float)should be different from Divide(int, int), but they're basically the same operation. Wouldn't you rather remember one method name, "Divide", than have to remember "DivideFloat", "DivideInt", "DivideIntByFloat", and so on?

重载不是必需的,但它有时确实使生活更轻松或更易读。可以说它会使情况变得更糟,但那是不应该使用的时候。例如,您可以有两个函数执行相同的操作,但作用于不同种类的事物。例如Divide(float, float)应该与 不同Divide(int, int),但它们的操作基本相同。您是否宁愿记住一个方法名称“Divide”,而不必记住“DivideFloat”、“DivideInt”、“DivideIntByFloat”等?

回答by paercebal

People already defined both overloading and overriding, so I won't elaborate.

人们已经定义了重载和覆盖,所以我不会详细说明。

ASAFEasked:

the only advantage [to overloading] is you haven't think in several names to functions?

ASAFE问:

[重载] 的唯一优点是您没有想到函数的几个名称?

1. You don't have to think in several names

1.你不必想几个名字

And this is already a mighty advantage, isn't it?

这已经是一个巨大的优势,不是吗?

Let's compare with known C API functions, and their fictional C++ variants:

让我们与已知的 C API 函数及其虚构的 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) ;

This means two things: One, you must tell the compiler the type of the data it will feed to the function by choosing the right function. Two, if you want to extend it, you'll need to find fancy names, and the user of your functions will have to remember the right fancy names.

这意味着两件事:第一,您必须通过选择正确的函数来告诉编译器它将提供给函数的数据类型。二,如果你想扩展它,你需要找到花哨的名字,你的函数的用户必须记住正确的花哨的名字。

And all he/She wanted was to have the absolute value of some numerical variable...

而他/她想要的只是一些数值变量的绝对值......

One action means one and only one function name.

一个动作意味着一个且只有一个函数名。

Note that you are not limited to change the type of one paramter. Anything can change, as long as it makes sense.

请注意,您不仅可以更改一个参数的类型。只要有意义,任何事情都可以改变。

2. For operators, it is mandatory

2.对于运营商来说,是强制性的

Let's see of operators:

让我们看看运营商:

// 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)
}

In the above example, you do wantto avoid using anything else than the + operator.

在上面的示例中,您确实希望避免使用除 + 运算符之外的任何其他内容。

Note that C has implicit operator overloading for built-in types (including C99 complex type):

请注意,C 对内置类型(包括 C99 复杂类型)具有隐式运算符重载:

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

So even in non-object languages, this overloading thing is used.

所以即使在非对象语言中,也会使用这种重载的东西。

3. For objects, it is mandatory

3.对于对象,它是强制性的

Let's see the use of an object basic methods: Its constructors:

让我们看看一个对象基本方法的使用:它的构造函数:

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

Some could consider this like function overloading, but in fact, it is more similar to operator overloading:

有些人可能会认为这类似于函数重载,但实际上,它更类似于运算符重载:

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" ;
}

Conclusion: Overloading is cool

结论:重载很酷

In C, when you give the name of the function, the parameters are implicitely part of the signature at call. If you have "double fabs(double d)", then while the signature of fabs for the compiler is the undecorated "fabs", it means that youmust know it takes only doubles.

在 C 中,当您给出函数的名称时,参数在调用时隐含地是签名的一部分。如果您有“double fabs(double d)”,那么编译器的 fabs 签名是未修饰的“fabs”,这意味着必须知道它只需要 doubles。

In C++, the name of the function does not mean its signature is forced. Its signature at call is its name and its parameters. Thus, if you write abs(-24), the compiler will know what overloading of abs it must call, and you, when writing it, find it more natural: You want the absolute value of -24.

在 C++ 中,函数的名称并不意味着它的签名是强制的。它在调用时的签名是它的名称和它的参数。因此,如果您编写 abs(-24),编译器将知道它必须调用什么 abs 重载,并且您在编写它时会发现它更自然:您需要 -24 的绝对值。

Anyway, anyone who coded somewhat in any language with operators already uses overloading, be it C or Basic numerical operators, Java string concatenation, C# delegates, etc.. Why? because it's more natural.

无论如何,任何用任何带有运算符的语言进行编码的人都已经使用了重载,无论是 C 还是基本数字运算符、Java 字符串连接、C# 委托等。为什么?因为它更自然

And the examples shown above are just the tip of the iceberg: When using templates, overloading become very very useful, but this is another story.

上面显示的示例只是冰山一角:使用模板时,重载变得非常有用,但这是另一回事。

回答by jdigital

The textbook example is class Animal with method speak(). The Dog subclass overrides speak() to "bark" while the Cat subclass overrides speak() to "meow".

教科书的例子是带有方法 speak() 的 Animal 类。Dog 子类将 speak() 覆盖为“bark”,而 Cat 子类将 speak() 覆盖为“meow”。

回答by David Thornley

One use of overloading is for use in templates. In templates, you write code that can be used on different data types, and call it with different types. If functions that take different arguments had to be named differently, the code for different data types would in general have to be different, and templates just wouldn't work.

重载的一种用途是在模板中使用。在模板中,您编写可用于不同数据类型的代码,并使用不同类型调用它。如果采用不同参数的函数必须以不同的方式命名,则不同数据类型的代码通常必须不同,模板就无法工作。

While you may not be writing templates yet, you're almost certainly using some of them. Streams are templates, and so are vectors. Without overloading, and therefore without templates, you'd need to call Unicode streams something different from ASCII streams, and you'd have to use arrays and pointers instead of vectors.

虽然您可能还没有编写模板,但您几乎肯定会使用其中的一些模板。流是模板,向量也是。如果没有重载,因此没有模板,您需要将 Unicode 流称为与 ASCII 流不同的东西,并且您必须使用数组和指针而不是向量。