C++ 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 {

来自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 {
    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();