隐藏在C ++中的名称隐藏静态成员函数:良好实践?

时间:2017-12-01 21:31:27

标签: c++ inheritance

在我作为C ++程序员的时候,我通常认为应该避免名称隐藏,因为它可能导致混淆。例如,如果你有一个带有函数f()的基类和一个带有函数f()的派生类,并且f()不是虚拟的,那么调用者可能会意外地调用错误的f()。

然而,我在阅读Herb Sutter的Exceptional C ++书籍时遇到了一个例子,其中似乎鼓励了一个隐藏名字的案例。为了创建一个不区分大小写的字符串,他建议我们通过创建一个继承自std::basic_string<>的{​​{1}}类来创建一个不区分大小写的char_traits版本(这是一个非多态的静态类)像这样:

char_traits<char>

(我省略了函数定义以使其更简洁)。本质上,我们继承了struct ci_char_traits : public char_traits<char> { static bool eq( char c1, char c2 ) { /*...*/ } static bool lt( char c1, char c2 ) { /*...*/ } static int compare( const char* s1, const char* s2, size_t n) { /*...*/ } static const char* find( const char* s, int n, char a ) { /*...*/ } } 的所有函数,我们隐藏了我们想要修改的函数,以使其不区分大小写。然后,您可以像这样定义不区分大小写的字符串:

char_traits<char>

现在我认为这是一个非常巧妙的技巧!但我想知道这种事情是否被认为是“良好实践”,因为隐藏名称通常是不受欢迎的。也许名称隐藏静态成员函数比其他类型的函数更容易接受?

2 个答案:

答案 0 :(得分:1)

这里的区别在于traits类不是多态的,所以对于使用哪个接口永远不会有任何混淆。

ci_char_traits当然可以通过私有继承,封装或简单地推迟到std::char_traits<>来实现。所有这些方法都需要更多的维护。

更新

评论中有关模板是否具有多态性的讨论。我会详细说明。

构造std::basic_string<char, ci_char_traits>导致模板std::basic_string<class CharT, class Traits, class Allocator>的模板扩展。在此扩展期间,进行以下类型替换:

  • CharT已替换为char
  • Traits已替换为ci_char_traits
  • Allocator已替换为std::allocator<char>

因此,编译器生成的类是:

std::basic_string<char, ci_char_traits, std::allocator<char>>

这不是一个多态类。

这个类将有一个名为std::basic_string<char, ci_char_traits, std::allocator<char>>::traits_type的成员typedef,它明确地是类型ci_char_traits

因此,此模板扩展将导致非多态类,该类使用非多态类ci_char_traits来确定基于字符的操作(如比较)的行为。

eq中的代码将调用ltstd::basic_string<char, ci_char_traits, std::allocator<char>>的哪个重载被精确定义,这就是为什么在这种情况下,重载这些静态成员的做法并不错功能。

答案 1 :(得分:0)

在不区分大小写的示例中,更多的是实现接口,只是因为这个接口是通过模板完成的,所以它是编译时的事情,而不是运行时。

要实现std :: char_traits,你根本不能使用不同的名称(至少没有使用basic_string进行大量修改),这些名称是接口的一部分。