C++ C+中继承函数重新定义的实际意义+;
来自Bruce Eckel的代码,用C++思考C++ C+中继承函数重新定义的实际意义+;,c++,inheritance,C++,Inheritance,来自Bruce Eckel的代码,用C++思考 class A { int i; public: A(int ii) : i(ii) {} ~A() {} void f() const {} }; class B { int i; public: B(int ii) : i(ii) {} ~B() { void f() const {} }; class C : public B {
class A {
int i;
public:
A(int ii) : i(ii) {}
~A() {}
void f() const {}
};
class B {
int i;
public:
B(int ii) : i(ii) {}
~B() {
void f() const {}
};
class C : public B {
A a;
public:
C(int ii) : B(ii), a(ii) {}
~C() {} // Calls ~A() and ~B()
void f() const { // Redefinition
a.f();
B::f();
}
};
int main() {
C c(47);
}
对于这个代码,他说
函数C::f()重新定义它继承的B::f(),并调用基类版本。此外,它还调用a.f()。请注意,您唯一可以谈论函数重新定义的时间是在继承期间;对于成员对象,您只能操作对象的公共接口,而不能重新定义它
他是什么意思
函数C::f()
只是通过作用域解析操作符调用B
的f()
。这是因为它是继承的,并且具有相同名称的函数也存在于C
中<通过类C
中定义的对象调用A的函数f()
那么,正如埃克尔所说,函数
f()
的重新定义在哪里呢?因为类C
是从B
派生出来的,函数C::f()
通过定义自己的版本来覆盖函数B::f()
。如果声明类型为C
的对象并调用其f()
函数,它将执行C::f()
,该函数可以完全独立于B::f()
。因此,基类函数被重新定义
请注意,类
C
还包含类型a
的成员,该成员还具有函数f()
,并且C
的f()
实现恰好调用a.f()
。因此C
可以为自己的f()
提供一个不同的接口,但它不能改变a的实现。如果删除了“C::f”的定义,仍然可以调用“C::f()”,因为它会被继承。但是在这个例子中,他选择了为C提供它自己的“f”实现。这对任何处理“C”类型对象的人“隐藏”了B::f函数。但它被称为“重新定义”,因为通过向下转换到父类型,任何查看“C”类型对象的人都无法看到该定义
考虑
#include <iostream>
using namespace std;
class A { void x() { cout << "A::x" << endl; } };
class A1 : public A {}; // No redefinition.
class A2 : public A { void x() { cout << "A2::x" << endl; A::x(); } };
int main(int argc, const char** argv)
{
A1 a1;
A2 a2;
cout << "a1: "; a1.x();
cout << "a2: "; a2.x();
A2* pa2 = &a2;
cout << " pa2: "; pa2->x();
A* pa = (A*)a2;
cout << "pa: " ; << pa;
return 0;
}
继承的全部要点是让您使用最小公分母,因此在本例中,您很可能要调用
/*account*/p -> Close();
这只能在账户中看到“关闭”的定义。因此,当您将SecureCount*添加到向量中,并试图在其仍有未结交易的情况下关闭它时,您将蒙受损失
为了了解如何解决这个问题,请继续阅读虚拟函数的解释。不同之处在于,如果您没有编写函数C::f
,但仍然在(静态)类型的对象上调用f
,如中所示
C c;
c.f();
如果不存在C::f
,这将调用B::f
(因为B
是C
的基类,而不是a::f
(因为那只是一个成员对象)。因此,函数C::f
的存在会导致调用C.f()
的语义发生变化
但是请注意,C::f
不会覆盖B::f
,因为B::f
不是虚拟的。也就是说,以下代码仍将调用B::f
,而不是C::f
:
C c;
B& b(c);
b.f();
如果B::f
是虚拟的,C::f
将覆盖它,并且该代码将调用C::f
。但是,由于B::f
不是虚拟的,C::f
不会覆盖它,因此上面的代码确实调用了B::f()
顺便说一句,我不同意布鲁斯·埃克尔的术语。在我看来,“重新定义”意味着取代定义。然而,C::f
并没有取代B::f
的定义,它只是隐藏了它。我想你被重新定义这个词弄错了。在这里,重新定义意味着覆盖派生类C中的方法f(),所以你的意思是就像再次编写它一样?我的意思是。。。当您在类设计中使用继承时,您主要尝试在基类中引入所有公共特性,而只在派生类中引入有区别的内容。假设我有一个基类Vehicle,它有一个更新vehicles wheel material组件的方法。现在将车辆派生为两个类。自行车和汽车。然后,您需要覆盖车辆的此更新方法,因为您可能需要在车辆的该方法中更新车轴信息,但并没有什么能像bicycle中的车轴一样,所以在这种情况下仍然使用基类vehicles方法。简单地说,当你们想要比基类更多或全新的行为时,你们需要覆盖。s/overwrite/override/+1 C::f不会覆盖B::f,因为B::f不是虚拟的,也不会重新定义B::f,因为这是胡说八道。
C c;
B& b(c);
b.f();