1
#include<iostream>

using namespace std;

class ParentClass {
public: 
     virtual void someFunc(int a){
        printf(" ParentClass :: someFunc (int) \n");
    };

    virtual void someFunc(int* a){
        printf(" ParentClass :: someFunc (int*) \n");
    };
};

class ChildClass : public ParentClass {
public:
    virtual void someFunc(int* a){
        printf(" ChildClass ::  someFunc(int*) \n");
    };
};

int main(){
    ChildClass obj;
    /* This function call results in an error: */
    obj.someFunc(7);
}

第一个给出错误为

tr2.cpp: In function 'int main()':
tr2.cpp:27:19: error: invalid conversion from 'int' to 'int*' [-fpermissive]
     obj.someFunc(7);
                   ^
tr2.cpp:18:18: error:   initializing argument 1 of 'virtual void ChildClass::som
eFunc(int*)' [-fpermissive]
     virtual void someFunc(int* a){
                  ^

但是如果我们将方法更改为接受 char 而不是 int* 那么

#include<iostream>

using namespace std;

class ParentClass {
public: 
     virtual void someFunc(int a){
        printf(" ParentClass :: someFunc (int) \n");
    };

    virtual void someFunc(char a){
        printf(" ParentClass :: someFunc (char) \n");
    };
};

class ChildClass : public ParentClass {
public:
    virtual void someFunc(char a){
        cout<<a<<endl;
        printf(" ChildClass ::  someFunc(char) \n");
    };
};

int main(){
    ChildClass obj;
    /* This function call results in an error: */
    obj.someFunc(7);
}

输出:

 ChildClass ::  someFunc(char)

伴随着窗户的声音(叮)。- ANS:这里是隐式转换。请检查下面的编辑。

所以名称隐藏在第一个示例中有效,但在第二个示例中不起作用。谁能解释为什么?我还尝试过使用不同数量的参数(如 int func(int a) 、 int func (int a, int b))制作重载的重写虚函数,然后只重写其中一个。在这种情况下,名称隐藏也不起作用,派生类能够派生未覆盖的基类的虚函数。

为什么这个名字隐藏只在这种特殊情况下有效?

编辑1:

With Context to Eternals 隐式转换的解释。我有另一个应该隐藏名称但没有的程序。在这个版本中,方法是根据不同的参数来区分的。

#include<iostream>

using namespace std;

class ABC
{   public:
    ABC()
    {
        cout<<"Constructor ABC"<<endl;
    }
    virtual void meth1(int a);
    virtual void meth2(int a, int b);
};

void ABC :: meth1(int a)
{
    cout<<"One"<<endl;
}   

void ABC:: meth2(int a, int b)
{
    cout<<"Two"<<endl;
}

class BC:public ABC
{
    public:
    BC()
    {
        cout<<"Cons B"<<endl;
    }

    void meth1(int a);
};

void BC :: meth1(int a)
{
        cout<<"Three"<<endl;
}

int main()
{
    BC b;
    b.meth1(5);
    b.meth2(6,7);
}

输出:

C:\Users\Shaurya\Desktop>a
Constructor ABC
Cons B
Three
Two

在这种情况下,名称隐藏也不起作用。

4

2 回答 2

6

当您重载someFunc()ChildClass,它会隐藏两个重载ParentClass。在第一种情况下,您正在调用一个int*以整数作为参数的函数,因此它当然会崩溃,因为它无法进行转换。

在第二种情况下,您正在调用一个函数,该函数将 achar作为带有整数的参数,因此存在隐式转换,一切都很好。

编辑 1 后更新:

我真的不明白你期望会发生什么:

  • 首先构造 a BC,它是 from 的子级ABC,所以调用ABC's 的构造函数 then BC's
  • 之后你打电话meth1():因为BC覆盖它,BC::meth1()所以被称为
  • 最后你打电话meth2():因为BC没有覆盖它,ABC::meth2()所以被称为

这里发生的唯一“名称隐藏”是 BC 对 meth1 的覆盖,但它并没有真正隐藏任何东西......

于 2014-10-14T18:11:19.277 回答
2

在您的“编辑 1”中,没有隐藏名称。在b.meth2(6,7)中找不到,所以在 中查找。但是如果你在程序中的任何地方重命名,它不会因为名称隐藏而编译:将隐藏。meth2BCABCmeth2meth1BC::meth1(int)ABC::meth1(int, int)

编辑:简要说明类成员查找的工作原理。当编译器看到static 类型object.method(args)哪里时,首先它会在 的声明中查找成员函数。如果它找到它(或者它是几个重载),它就会停止寻找其他任何地方。如果没有,它会按照 C++ 标准部分中完全描述的一些神秘规则在 的基类中查找它。objectclass Cmemberclass CmemberC10.2 Member name lookup

一旦找到候选者,编译器就会检查是否可以使用给定的参数调用任何候选者。如果是,并且可以明确地做到这一点,则找到该功能。否则程序是格式错误的。此过程称为重载解决方案,并在标准的一部分13.3中进行了描述。

请注意,virtual上面的解释中没有单词。

于 2014-10-14T19:36:01.983 回答