名称隐藏在c ++中

时间:2014-10-14 17:56:33

标签: c++ name-hiding

#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)

带有窗户声音(ding)。 - ANS:隐式转换。请检查下面的编辑。

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

为什么隐藏此名称仅适用于此特定情况?

编辑1:

使用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

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

2 个答案:

答案 0 :(得分:6)

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

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

编辑后更新:

我没有真正得到你期望会发生的事情:

  • 首先构建BC,这是来自ABC的孩子,因此调用ABC的构造函数然后调用BC&#39 ; S
  • 之后,您致电meth1():由于BC会覆盖它,因此BC::meth1()会被调用
  • 最后你致电meth2():由于BC没有覆盖它,ABC::meth2()被称为

唯一隐藏的名字&#34;这里发生的是BC的覆盖meth1,但它并没有隐藏任何东西......

答案 1 :(得分:2)

在你的“编辑1”中,没有隐藏的名字。 b.meth2(6,7) meth2找不到BC,因此会在ABC中查找meth2。但是,如果您在程序中的任何位置将meth1重命名为BC::meth1(int),则由于名称隐藏而无法编译:{{1​​}}将隐藏ABC::meth1(int, int)

编辑:关于类成员查找如何工作的简要说明。当编译器看到object.method(args)时,object静态类型class C,首先它会在member的声明中查找成员函数class C {1}}。如果它找到它(或者它有几次重载),就会停止在其他任何地方寻找member 。如果没有,它会在C的基类中查找它,遵循C ++标准部分10.2 Member name lookup中完整描述的一些神秘规则。

一旦找到候选者,编译器将检查是否可以使用给定参数调用任何候选者。如果是,并且可以无差别地完成,则找到该功能。否则该计划是不正确的。此过程称为重载决策,并在标准的13.3部分中进行了描述。

请注意,上述说明中没有单词virtual