【问题标题】:Name hiding in c++隐藏在 C++ 中的名称
【发布时间】:2014-10-14 17:56:32
【问题描述】:
#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

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

【问题讨论】:

  • 附注:为什么coutprintf() 的奇怪组合??
  • 'int' 和 'char' 重载不明确。
  • 我从一个网站上复制了这个例子,看看其他不同的案例。网站上提到的案例是为了隐藏名字。但我试过的情况没有。我使用更多的 cout,他们使用 printf。
  • 第二个版本中没有int*,我看不出错误消息是如何引用的。你确定你复制的正确吗?
  • 错误信息对应第一个程序

标签: c++ name-hiding


【解决方案1】:

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

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

编辑 1 后更新:

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

  • 首先你构造了一个BC,它是ABC的一个孩子,所以会调用ABC的构造函数,然后是BC的构造函数
  • 之后你调用meth1():因为BC 覆盖它,BC::meth1() 被调用
  • 最后你调用meth2():因为BC没有覆盖它,ABC::meth2()被调用

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

【讨论】:

  • 请检查编辑。我考虑过隐式转换,这可能发生在那里,我没有注意到它的子类函数正在被调用。无论如何,我已经编辑并附加了主要问题,其中父类函数被调用,而只有一个方法被覆盖。
【解决方案2】:

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

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

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

注意上面的解释中没有virtual这个词。

【讨论】:

  • 谢谢。所以这只适用于重载的重写方法。而其他虚方法完全不受影响?
  • 我不太明白你的问题。我在答案中添加了成员​​查找的简短说明。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-01
  • 2017-05-06
  • 1970-01-01
  • 2012-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多