为什么我要使用 "using" 关键字来访问基类的方法?

80
我编写了下面的代码来解释我的问题。如果我注释掉第11行(使用关键字“using”),编译器将无法编译文件并显示此错误:invalid conversion from 'char' to 'const char*'。它似乎无法在Son类中看到Parent类的void action(char)方法。

为什么编译器会这样呢?或者我做错了什么吗?

class Parent
{
    public:
        virtual void action( const char how ){ this->action( &how ); }
        virtual void action( const char * how ) = 0;
};

class Son : public Parent
{
    public:
        using Parent::action; // Why should i write this line?
        void action( const char * how ){ printf( "Action: %c\n", *how ); }
};

int main( int argc, char** argv )
{
    Son s = Son();
    s.action( 'a' );
    return 0;
}

请告诉我:如果在“const char how”中删除const会怎样? - Pavel Radzivilovsky
35
不需要输入 Son s = Son();,这只会创建一个临时对象并调用复制构造函数。只需输入 Son s; 即可。 - Charles Salvia
1
为什么C++被设计成那样的版本:https://dev59.com/KW445IYBdhLWcg3we6V9 - Ciro Santilli OurBigBook.com
不需要使用难以理解的 using ...,像新语言(例如 TypeScript)一样使用 this->action(...) 来避免错误。 - Top-Master
5个回答

66

派生类中声明的action会隐藏基类中声明的action。如果在Son对象上使用action,编译器将在Son中声明的方法中查找名为action的方法,并使用它。它不会继续在基类的方法中搜索,因为它已经找到了匹配的名称。

然后该方法与调用的参数不匹配,您将收到错误消息。

有关此主题的更多解释,请参见C++ FAQ


11
好的,知道了。但是这个问题,可以说是C++的一个特性还是某种类型的错误吗?这不会破坏继承的整个概念吗?只是问一下。 - Anubis
名称匹配是使用重载方法还是使用修饰后的名称完成的?或者只是调用了第一个名称为“action”的函数? - tmaric
5
@Anubis:这条规则简化了名称查找过程。如果没有这个规则,当编译器需要解析成员函数的名称时(在某个基类中可能有该函数的重载版本),它需要遍历整个继承树。有了这个规则,一旦找到一个包含匹配名称的类,编译器就可以停止查看继承树的其余部分。程序员也处于相同的情况。通过查看派生类,他可以确信将调用在其中定义的函数,而不需要知道某个基类是否可能包含相同名称的不同函数。 - sth

21

令人惊讶的是,这是标准的行为。如果派生类声明了与基类定义的方法同名的方法,则派生类的方法会隐藏基类的方法。

请参见C++ FAQ


6
注意事项:在这种情况下需要使用“using”可能会让其他开发者感到困惑(毕竟编译器也被搞糊涂了!)。很可能你应该重新命名其中一个方法,以便让其他程序员清楚地区分它们。
一种可能的解决方案:
void action( const char how )
{ 
  takeAction( &how ); 
}
void action( const char * how )
{
  takeAction(how);
}
virtual void takeAction(const char * how) = 0;

6

如果在派生类中重新定义了任何重载函数,则基类中所有重载函数都会被隐藏。 一个解决方法是避免在类中进行函数重载。或者, 您可以使用using关键字,如下所示。


我有一个基类,其中包含大量方法,对于每个方法都使用 base::method 进行编写非常繁琐。是否有一种方法可以使用单个 using 声明来完成这个过程? - 0xB00B

0
通过使用using,将基类中声明的名称引入到派生类的命名空间中。
然后,在派生类中声明一组函数时,编译器通过隐式this指针的类型将其与具有相同参数类型的基类中的函数区分开来。
在重载决议期间,需要进行类类型转换的参数(当将指向派生类的指针转换为指向基类的指针时会发生这种情况)优先级最低。
因此,具有看似相同参数列表的两个函数可以被区分开来,当从派生类型的对象调用它们时,局部声明的函数将是更好的(如果不是完全匹配)。
我是新手,请指出我的误解。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接