C ++继承相同类型签名的成员函数(shadowing)

时间:2013-03-31 21:10:28

标签: c++

 // Shadowing

 #include <iostream>
 using namespace std;
 const int MNAME = 30;
 const int M  = 13;

 class Person {   // Base Class
     char person[MNAME+1];
   public:
     void set(const char* n);
     void display(ostream&) const;
   protected:
     const char* name() const;
 };

 void Person::set(const char* n) {
     strncpy(person, n, MNAME);
     person[MNAME] = '\0';
 }

 void Person::display(ostream& os) const {
     os << person << ' ';
 }

 const char* Person::name() const { return person; }

 class Student : public Person { // Derived
     int no;
     char grade[M+1];
   public:
     Student();
     Student(int, const char*);
     void display(ostream&) const;
 };

 Student::Student() {
     no = 0;
     grade[0] = '\0';
 }

 Student::Student(int n, const char* g) {
     // see p.61 for validation logic
     no = n;
     strcpy(grade, g);
 }

 void Student::display(ostream& os) const {
     os << name() << ' '
        << no << << ' ' << grade << endl;
 }

 int main() {
     Person person;
     Student student(975, "ABBAD");

     student.set("Harry");
     student.display(cout); // Harry 975 ABBAD

     person.set("Jane Doe");
     person.display(cout); // Jane Doe
 }
  

第一次调用display()(在student上)调用Student的版本   显示()。第二次调用display()(on person)调用Person   版本的display()。 display()的派生版本会影响   学生对象的基础版本。基本版本在。上执行   人物。

我不明白那是什么影子。我意识到这两个类都定义了相同的显示功能,显然如果你调用student.display和person.display,它会相应地调用它们。那么这意味着什么:

  

display()的派生版本会影响基础版本   学生对象。基础版本在person对象上执行。

我不明白阴影。

来源:https://scs.senecac.on.ca/~btp200/pages/content/dfunc.html 继承 - 派生类的功能

3 个答案:

答案 0 :(得分:2)

您的Student类继承自Person。这意味着Student对象来自Student中定义的所有内部结构以及Person中定义的所有内部结构 - 对于此问题Student可以看出包含Person。这意味着Student对象包含两个版本的display方法 - 一个来自基类,另一个来自派生。阴影意味着当从派生对象调用display时,它将调用派生类版本,并且基类版本被它“遮蔽”而不被调用。您可以通过使用基类前缀Student显式指定它来从Person::display内调用阴影版本。通常,将被调用的函数是最接近范围的函数 - 对于Derived对象,它是Derived的范围,驻留在外部作用域(例如base)中的函数被遮蔽。

答案 1 :(得分:0)

这意味着您很可能错过virtual

例如,您的Person类应该看起来像:

 class Person {   // Base Class
     char person[MNAME+1];
   public:
     void set(const char* n);
     virtual void display(ostream&) const;
   protected:
     const char* name() const;
 };

现在,如果您有以下代码:

Person* student = new Student(975, "ABBAD")
student->set("Harry");
student->display(cout);

您的输出将是“Harry”而不是“Harry 975 ABBAD \ n”。正如icepack所说,你收到消息的原因是因为Student类中的display方法“遮蔽”Person类中的display方法,并且因为你没有声明该方法是虚拟的,所以编译器认为阴影是偶然的。如果这不是偶然的,那么你应该声明该方法是虚拟的。

答案 2 :(得分:0)

尝试这个小实验。定义以下功能:

void person_display(Person &p){
    p.display(cout);
}

然后让mainpersonstudent上调用它。

int main(){
   // [...]
   person_display(person);
   person_display(student);

}

在这两种情况下,您都会看到方法Person::display将被调用。由于在其祖先类的一类方法中重新定义,因此阴影是一种现象。它会影响先前的定义,只要该实例被视为子类,但只要它被视为祖先,阴影就会消失。

这与virtual方法形成对比,其中被调用的方法始终是在实例类中定义的方法,即。在上述实验中,您会看到调用Student方法,即使它被视为简单的Person