C++中的重定义与重写

6ss1mwsb  于 2023-01-03  发布在  其他
关注(0)|答案(2)|浏览(186)

我对派生类中重定义函数和重写函数之间的区别感到困惑。
我知道,在C++中,重定义函数是静态绑定的,重写函数是动态绑定的,虚函数被重写,非虚函数被重定义。
当一个派生类“重定义”一个基类中的一个方法时,它被认为是重定义。但是当一个派生类是虚的时,它不再重定义而是重写。所以我理解规则的逻辑,但我不理解底线。
在下面的例子中,函数SetScore被重新定义。但是,如果我在基类中使setScore函数成为virtual(通过添加单词virtual到它),则派生类中的setScore将被覆盖。我不明白底线-在setScore中有什么区别?
基类:

class GradedActivity
{
protected:
   char letter;            // To hold the letter grade
   double score;           // To hold the numeric score
   void determineGrade();  // Determines the letter grade
public:
   // Default constructor
   GradedActivity()
  { letter = ' '; score = 0.0; }

 // Mutator function
   void setScore(double s) 
      { score = s;
        determineGrade();}

   // Accessor functions
   double getScore() const
      { return score; }

       char getLetterGrade() const
      { return letter; }
};

派生类:

class CurvedActivity : public GradedActivity
{
protected:
   double rawScore;     // Unadjusted score
   double percentage;   // Curve percentage
public:
   // Default constructor
   CurvedActivity() : GradedActivity()
      { rawScore = 0.0; percentage = 0.0; }

   // Mutator functions
   void setScore(double s) 
      { rawScore = s;
        GradedActivity::setScore(rawScore * percentage); }

   void setPercentage(double c)
      { percentage = c; }

   // Accessor funtions
   double getPercentage() const
      { return percentage; }

   double getRawScore() const
      { return rawScore; }
};

这主要是:

// Define a CurvedActivity object.
   CurvedActivity exam;

   ... 

   // Send the values to the exam object.
   exam.setPercentage(percentage);
   exam.setScore(numericScore);
vsnjm48y

vsnjm48y1#

以下是一些基本区别:

重载函数是一个与一个或多个其他函数共享名称,但参数列表不同的函数。编译器根据所使用的参数选择所需的函数。
overrided函数是子类中的方法,它与祖先类中的虚函数具有不同的定义。编译器根据用于调用函数的对象类型来选择所需的函数。

一个重定义的函数是一个子类中的方法,它与一个祖先类中的非虚函数有不同的定义。不要这样做。因为这个方法不是虚的,编译器根据对象引用的静态类型而不是对象的实际类型来选择调用哪个函数。

*静态类型检查意味着类型检查发生在编译时。在这种情况下,运行时不使用类型信息。
*动态类型检查在运行时使用类型信息时发生。C++使用一种称为RTTI(运行时类型信息)的机制来实现这一点。使用RTTI的最常见示例是dynamic_cast运算符,它允许多态类型的向下转换:

piv4azn7

piv4azn72#

对劳伦斯·艾洛回答的举例

函数重载(必须在相同范围内)

int add(int a, int b) {
    return a + b;
}

double add(double a, double b) {
    return a + b;
}

函数重新定义:

class Base {
public:
    // notice that the function is NOT virtual
    void greetings() const {
        cout << "Hi, I'm from Base class" << endl;
    }
};

class Base : public Derived {
public:
    // redefinition of the function
    void greetings() const {
        cout << "Hi, I'm from Derived class" << endl;
    }
};

Base b;
b.greetings(); // Output: Hi, I'm from Base class
// static binding

Derived d;
d.greetings();  // Output: Hi, I'm from Derived class
// static binding

Base *b_ptr = new Derived();
b_ptr->greetings(); // Output: Hi, I'm from Base class <== PROBLEM
                    // Expected: Hi, I'm from Derived class
// static binding
// Compiler all knows that b_ptr is a pointer to Base object, so it binds the
// method Base::greetings at compile time.

函数覆盖:

class Base {
public:
    // notice that the function is virtual
    virtual void greetings() const {
        cout << "Hi, I'm from Base class" << endl;
    }
};

class Base : public Derived {
public:
    // overriding the function
    void greetings() const {
        cout << "Hi, I'm from Derived class" << endl;
    }
};

Base b;
b.greetings(); // Output: Hi, I'm from Base class
// static binding

Derived d;
d.greetings();  // Output: Hi, I'm from Derived class
// static binding

Base *b_ptr = new Derived();
b_ptr->greetings();   // Output: Hi, I'm from Derived class (Expected)
// dynamic binding
// The idea of using virtual functions tells the compiler NOT to bind the 
// method at compile-time, but instead defer to run-time.

相关问题