【问题标题】:C++ inheriting member functions of the same type signature (shadowing)C++ 继承同类型签名的成员函数(shadowing)
【发布时间】:2013-03-22 00:04:34
【问题描述】:
 // 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() (on person) 调用 Person display() 的版本。 display() 的派生版本遮蔽了 学生对象的基础版本。基本版本在 人对象。

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

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

我不懂阴影。

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

【问题讨论】:

  • 想象一下你想在student上调用person版本。

标签: c++


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    这意味着您很可能错过了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,编译器假定遮蔽是偶然的.如果这不是偶然的,那么您应该将该方法声明为虚拟的。

    【讨论】:

    • 这个问题是关于阴影的。没有理由认为这是一个错误并谈论覆盖。此外,编译器不会假设任何意外,遮蔽是一个有效条件。
    • 如果这不是一个错误(而且在我看来肯定是一个错误),那么至少应该在 Person 代码的行中添加一条注释,解释 display 不应该是虚拟的以及为什么. (但是,是的,我是编译器的拟人化,并且遮蔽是语法正确,但它是否有效取决于一个人对该词的用法。)
    【解决方案3】:

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

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

    然后让mainpersonstudent 上调用它。

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

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

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

    【讨论】:

      猜你喜欢
      • 2011-02-07
      • 2011-06-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-30
      • 1970-01-01
      • 1970-01-01
      • 2011-01-16
      相关资源
      最近更新 更多