【问题标题】:C++ method implementations: Can I avoid typing the class name each time?C++ 方法实现:我可以避免每次都输入类名吗?
【发布时间】:2020-04-27 04:27:51
【问题描述】:

当我在命名空间 mynamespace 中有一个 C++ 类 MyClass 时,我将其方法实现为

void mynamespace::MyClass::method() { … }

我可以将其包装在命名空间中以将单个定义缩短为

namespace mynamespace {

    void MyClass::method() { ... }

}

有没有办法避免重新输入MyClass::,这样我就可以在签名更改时更轻松地将{ 之前的所有内容作为原型复制到标题中,而不必每次都删除MyClass:: ?

我想“一个类也是一个命名空间,也许我可以做到”

namespace mynamespace::MyClass {

    void method() { ... }

}

但这抱怨我将 MyClass 重新定义为不同的东西。 using mynamespace::MyClass; 也不起作用(但无论如何都会很糟糕,因为如果它起作用,我将如何在该文件中该行下方的任何位置声明一个独立函数)。

是否有解决方案,或者在 C++ 中根本不可能?

【问题讨论】:

  • (99% 确定)不。类名必须出现,否则不知道该方法属于哪个类。
  • 当然,您可以在实现类的同时实现您的方法。但我有一种感觉,这不是你想听到的。
  • 如果你使用 IDE,你可以使用自动补全
  • 添加到@foreknownas_463035818,一些IDE还可以“复制签名”函数
  • 如果头文件中还没有新方法的声明,则无法自动完成,通常IDE会根据头文件自动完成,所以如果我编辑实现,我无法自动完成遗憾的是,将实现的签名编辑到标题中。

标签: c++ namespaces code-formatting


【解决方案1】:

使用 C++20 模块,您可以在一个文件中实现一个类:

module myproject.mymodule;

namespace mynamespace {
    export struct my_class {
        auto my_method() -> int {
            return 8;
        }
    };
}

或者导出整个命名空间片段:

export namespace mynamespace {
    struct my_class {
        auto my_method() -> int {
            return 8;
        }
    };

    auto also_exported() -> void {
        // ...
    }
}

然后,您可以导入该模块,而不是包含它:

import myproject.mymodule;

auto frob() -> void {
    auto my_instance = mynamespace::my_class{};
}

【讨论】:

  • 但是我们仍然需要在类定义中定义函数,不是吗?如果在外面定义它们,我们将不得不再次重复类名,不是吗?
  • @Aconcagua 当然可以,但是有了模块,你就没有在标题中放一些东西的缺点,消除了分离定义的大部分需要。
  • 好吧,我们也可以在头文件中实现整个类。在重复类范围方面,我看不出这与模块内容有何不同...
  • @Aconcagua 是的。您可以将整个代码库放入标题中。我们不这样做是有原因的。模块对此有很大帮助,因为您可以将整个代码库放入接口中而几乎没有缺点。
  • 如果你看看像 Swift 这样的语言,你没有理由不能从模块文件动态地生成用户可读的头文件。这样做的好处是您可以省略某些内容,例如受保护的方法和私有方法,从而更好地封装实现细节,同时节省容易出错的复制粘贴来生成原型。
【解决方案2】:

没有惯用的方法来避免这种情况。即使您或其他人可能想出一个“hack”(例如,基于宏的),它也会使每个人的代码可读性降低。编写 C++ 的正常和预期方式是,在类定义之外定义成员函数时,具有前面的 MyClass::

我建议寻找一个可以在命令上更新头文件和源文件之间签名的工具。

或者,正如 cmets 建议的那样,在类定义中的声明中提供函数的定义(即提供内联定义)。但这有它自己的缺点。

【讨论】:

    【解决方案3】:

    不,合格的类名必须出现在类定义之外定义的任何类成员上。 (并且只能有一个类定义,通常在头文件中。)

    C++ 标准在[class.mfct]/4 中阐明了这条规则:

    如果成员函数的定义在词法上超出其类定义,则成员函数名称应使用​::​运算符由其类名限定。

    [class.static.data]/2 中同样适用于静态数据成员。

    您可以使用预处理器宏来缩写此限定,但这会严重损害易读性并且不是常见的做法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 2022-10-06
      • 1970-01-01
      • 1970-01-01
      • 2020-08-25
      • 1970-01-01
      相关资源
      最近更新 更多