1

这是我记得的:

在 C++ 中,如果派生类定义了一个与基类具有相同名称但签名(参数等)不同的成员函数,它将在基类中“隐藏”相应的成员函数。例如

class Base {
public:
  void virtual f(double x); 
};

class Derived : public Base {
public:
  void f(char c); 
};

int main()
{
  Derived* d = new Derived();
  Base* b = d;
  b->f(65.3);  // call f(double x)
  d->f(65.3);  // call f(char c)
  delete d;
  return 0;
}

如果我错了,请纠正我,但我认为在 C++ 中说“隐藏”,这也意味着派生类看不到“f(double x)”,或者换句话说,派生类没有“f(double x)”作为它从 Base 继承的成员函数,对吗?

在 Java 教程中,“隐藏”实际上意味着其他东西(对于静态类方法),而对于实例方法,您可以重载从基类继承的方法。看这个例子:使用继承的重载方法

public class ClassA {
    public void method(Number n) {
        System.out.println("ClassA: " + n + " " + n.getClass());
    }
}

public class ClassB extends ClassA {            
    public void method(Integer d) {
        System.out.println("ClassB: " + d + " " + d.getClass());
    }
}

ClassA a = new ClassB(); 
a.method(3);

在 C++ 类型的思维中,基于 C++ 中的“动态绑定”和“隐藏”思想,我会得到与调用 A 类的“方法(编号 n)”相同的结果,但是:

  1. 我仍然不确定如何用 Java 解释它。该链接本身使用“在编译时选择方法签名”和“它实际上是从 B 类调用”来解释;但是在 C++ 的思想中,前者是可以的,但我不认为它是从 B 类调用的,它应该是从 A 类调用的,对吧?

  2. 使用继承的重载方法和Java教程中,'Class B'允许从'Class A'重载函数,并且'Class B'实际上可以看到'method(Number n)''method(Integer d)'。所以 C++ 和 Java 对待重载的方式不同,对吧?为什么是这样?在 C++ 示例中说,如果 Derived 也允许重载,则 'd->f(65.3)' 将调用 'f(double x)',而不是 'f(char c)'。

谢谢,

4

2 回答 2

2

在 C++ 中,对于非虚拟函数来说,每件事都是静态的,所以对于非虚拟函数,你没有dynamic-binding. 并且隐藏不会从继承中删除功能。是这样的:

当您将方法定义M为:void M(int)然后编译器在内部实现一个函数,名称Base::Mvoid Base::M( Base* this, int ). 现在这个函数是在代码中的某个地方实现的,不能删除,只要你能提供 this 就可以调用它(实际上你甚至可以在没有 this 的情况下调用它)。所以在Child我可以调用Base::M(0);和 C++ 转换为this和调用. 当你定义一个函数,其名称对应于基类的名称时,你告诉编译器我更喜欢在我的类中使用该名称作为新方法或属性!但是您不会删除任何东西,您可以使用to 的旧定义:Child*Base*MusingMChild

struct Base {
    void f( int ) {}
};
struct Child : Base {
    void f( char* ) {}
    using Base::f;  // Bring Base::f to this class, so I have f(char*), f(int)
};

除此之外,您f(int)甚至可以在不使用using.

// In the Child class
void test() {
    Base::f('c');  // Call Base::f(char)
}

// Outside of class
Child c;
((Base*)&c)->f('1');
于 2012-10-13T08:17:15.923 回答
1

这不是我期望 C++ 的行为方式。与其隐藏基类方法,不如让子类简单地重载该方法,因为参数不同。因此,当您调用 b->f() 时,编译器将知道使用哪种方法,因为只有一种可用,但它必须根据您的参数类型确定在您调用 d->f() 时使用哪种方法。如果它不能,那么在编译时你将被迫使用强制转换。在您的示例中,它应该识别小数点并使用 double 来代替 char。

于 2012-10-13T06:24:54.393 回答