// 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 继承 - 派生类的功能
答案 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);
}
然后让main
在person
和student
上调用它。
int main(){
// [...]
person_display(person);
person_display(student);
}
在这两种情况下,您都会看到方法Person::display
将被调用。由于在其祖先类的一类方法中重新定义,因此阴影是一种现象。它会影响先前的定义,只要该实例被视为子类,但只要它被视为祖先,阴影就会消失。
这与virtual
方法形成对比,其中被调用的方法始终是在实例类中定义的方法,即。在上述实验中,您会看到调用Student
方法,即使它被视为简单的Person
。