2
 // 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() 的第一次调用(在学生上)调用 display() 的学生版本。对 display() 的第二次调用(在 person 上)调用 display() 的 Person 版本。display() 的派生版本在学生对象上隐藏了基础版本。基本版本在 person 对象上执行。

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

display() 的派生版本在学生对象上隐藏了基础版本。基本版本在 person 对象上执行。

我不明白阴影。

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

4

3 回答 3

2

你的Student类继承自Person. 这意味着,除其他外,Student对象由定义的所有内部Student和定义的所有内部组成Person- 因为这个问题Student可以被视为包含Person. 这意味着Studentobject 包含两个版本的display方法 - 一个来自基类,一个来自派生类。Shadowing 是指display从派生对象调用时,会调用派生类版本,而基类版本被它“遮蔽”而不被调用。Student您可以通过使用基类前缀显式指定它来从内部调用影子版本: Person::display。通常,将被调用的函数是范围内最接近的函数 - 对于Derived它是作用域的对象Derived和驻留在外部作用域(例如基础)中的函数被隐藏起来。

于 2013-03-31T21:17:52.857 回答
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 方法,并且由于您没有声明该方法 virtual,编译器假定遮蔽是偶然的. 如果这不是偶然的,那么您应该将该方法声明为虚拟的。

于 2013-03-31T21:18:03.873 回答
0

试试这个小实验。定义以下函数:

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

然后main调用它personstudent

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

}

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

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

于 2013-03-31T21:35:37.110 回答