这是我记得的:
在C ++中,如果派生类定义了一个具有相同名称但与基类不同的签名(参数等)的成员函数,它将“隐藏”基础中的相应成员函数。 e.g。
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(双x)',或者换句话说,Derived没有'f(double x)'作为Base的继承成员函数,对吗?
在Java教程中,'hide'实际上意味着其他东西(对于静态类方法),而对于例如方法,您可以重载从base继承的方法。看一下这个例子:Using inherited overloaded methods
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)'相同的结果,但是:
我仍然不确定如何用Java解释它。链接本身解释使用'方法签名是在编译时选择'和'它实际上是从B类调用';但是在C ++思考中,前者是可以的,但我不认为它是从B类调用的,它应该是从A类调用,对吗?
在Using inherited overloaded methods和Java教程中,'B类'允许从'A类'重载功能,'B类'实际上可以看到两个'方法(数字n)'和'方法(整数d)'。所以C ++和Java正在以不同的方式处理重载,对吗?那为什么呢?比如在C ++示例中,如果Derived也允许重载,'d-> f(65.3)'将调用'f(double x)',而不是'f(char c)'。
谢谢,
答案 0 :(得分:2)
在C ++中,对于非虚函数,每个事物都是静态的,因此对于非虚函数,您没有dynamic-binding
。并且隐藏不会从继承中删除函数。它是这样的:
当您将方法M
定义为:void M(int)
时,编译器会在内部将函数Base::M
实现为void Base::M( Base* this, int )
。现在这个函数在代码中的某个地方实现,无法删除,只要你能够提供这个功能就可以调用它(实际上你可以在没有这个的情况下调用它)。因此,在Child
中,我可以调用Base::M(0);
和C ++将this
从Child*
转换为Base*
并调用M
。当您定义一个函数,其名称对应于基类的名称时,您告诉编译器我更喜欢在我的类中使用该名称作为新方法或属性!但是你不删除任何内容,你可以使用using
将M
的旧定义带到Child
:
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');
答案 1 :(得分:1)
这不是我期望C ++表现的方式。我不希望隐藏基类方法,而是希望子类简单地重载方法,因为参数不同。因此,当你调用b-> f()时,编译器将知道使用哪种方法,因为只有一个可用,但是当你根据参数调用d-> f()时,它必须确定使用哪一种方法类型。如果它不能在编译时,你将被迫使用强制转换。在你的例子中,它应该识别小数点,如果是char,则使用double。