c ++中的扩展方法

我在c ++中寻找一个扩展方法的实现,并且在这个comp.std.c ++的讨论中提到了polymorphic_map可以被用来和一个类关联的方法,但是提供的链接似乎是死的。 有人知道这个答案是指什么,或者如果有另一种方式扩展类的扩展方法类似的方式(也许通过一些使用mixin?)。

我知道规范的C ++解决scheme是使用自由函数; 这比其他任何事情都好奇。

不同的语言以不同的方式进行开发。 特别是C#和Java对于面向对象有一个强烈的观点,导致一切都是对象思维(C#稍微松懈一些)。 在这种方法中,扩展方法提供了扩展现有对象或接口以添加新特征的简单方法。

C ++中没有扩展方法,也不需要。 在开发C ++时,忘记所有的东西都是对象范例 – 顺便说一句,即使在Java / C# [*]中也是错误的。 在C ++中采用了不同的思维方式,有对象,对象具有本质上是对象一部分的操作,但也有其他操作构成了接口的一部分,不需要成为类的一部分。 一个必须读草药萨特是什么在一个类? ,作者辩护(我同意),你可以轻松地扩展任何给定的类与简单的免费function。

作为一个特别简单的例子,标准模板类basic_ostream有几个成员方法来转储一些基本types的内容,然后用(也是模板化的)免费函数进行增强,这些函数通过使用现有的公共接口。 例如, std::cout << 1; 是作为成员函数实现的,而std::cout << "Hi"; 是以其他更基本的成员来实现的免费function。

C ++中的可扩展性是通过自由函数实现的,而不是通过向现有对象添加新方法的方式来实现的。

[*]一切都不是一个对象。

在给定的域中将包含一组可以build模的实际对象和可以应用于它们的操作,在某些情况下,这些操作将成为对象的一部分,但在其他情况下,它们不会。 特别是你会发现语言中的实用程序类声称,一切都是一个对象,这些实用程序类只是一个层,试图隐藏这些方法不属于任何特定对象的事实。

即使是作为成员函数实现的一些操作也不是对象的真正操作。 考虑Complex类的sum ,第一个参数比第二个参数的sum (或+ )多一个? 为什么a.sum(b);b.sum(a) ,如果不是sum( a, b )

强制操作成员方法实际上产生奇怪的效果 – 但我们只是习惯于他们: a.equals(b);b.equals(a); 即使equals的实现是完全对称的,也可能有完全不同的结果。 (考虑当ab是空指针时会发生什么)

Boost Range Library的方法使用运算符|()。

 r | filtered(p); 

我也可以用同样的方法写如下的string。

 #include <string> namespace string_extension { struct trim_t { std::string operator()(const std::string& s) const { ... return s; } }; const trim_t trim = {}; std::string operator|(const std::string& s, trim_t f) { return f(s); } } // namespace string_extension int main() { const std::string s = " abc "; const std::string result = s | string_extension::trim; } 

简单的答案是,你不能这样做。 长的答案是,你可以模拟它,但要知道,你将不得不创build大量的代码作为解决方法(实际上,我不认为有一个优雅的解决scheme)。

在讨论中,运营商提供了一个非常复杂的解决方法 – (在我看来,这是一个坏主意)。 我想死链接中提供的解决scheme更不相似(因为它是基于运营商|)。

这是基于能够做到或多或less与运营商的扩展方法相同的东西的能力。 例如,如果你想为你的新类Foo重载ostream的operator <<,你可以这样做:

 class Foo { friend ostream &operator<<(ostream &o, const Foo &foo); // more things... }; ostream &operator<<(ostream &o, const Foo &foo) { // write foo's info to o } 

正如我所说,这是C ++中唯一可用于扩展方法的类似机制。 如果你可以自然地把你的函数翻译成一个重载的操作符,那就没问题。 唯一的可能是人为地重载一个与你的目标毫无关系的操作符,但是这会让你编写非常混乱的代码。

我能想到的最类似的方法将意味着创build一个扩展类,并在那里创build你的新方法。 不幸的是,这意味着你需要“适应”你的对象:

 class stringext { public: stringext(std::string &s) : str( &s ) {} string trim() { ...; return *str; } private: string * str; }; 

然后,当你想要做这些事情:

 void fie(string &str) { // ... cout << stringext( str ).trim() << endl; } 

如上所述,这不是完美的,我不认为这种完美的解决scheme存在。 抱歉。

这是我见过的最接近于C ++扩展方法的东西。 就我个人而言,我喜欢它可以使用的方式,可能这是我们可以用这种语言进行扩展的最接近的方法。 但是有一些缺点:

  • 实施起来可能很复杂
  • 运算符优先级可能不是那么好,这可能会导致惊喜

一个办法:

 #include <iostream> using namespace std; class regular_class { public: void simple_method(void) const { cout << "simple_method called." << endl; } }; class ext_method { private: // arguments of the extension method int x_; public: // arguments get initialized here ext_method(int x) : x_(x) { } // just a dummy overload to return a reference to itself ext_method& operator-(void) { return *this; } // extension method body is implemented here. The return type of this op. overload // should be the return type of the extension method friend const regular_class& operator<(const regular_class& obj, const ext_method& mthd) { cout << "Extension method called with: " << mthd.x_ << " on " << &obj << endl; return obj; } }; int main() { regular_class obj; cout << "regular_class object at: " << &obj << endl; obj.simple_method(); obj<-ext_method(3)<-ext_method(8); return 0; } 

这不是我个人的发明,最近我的一个朋友把它邮寄给我,他说他是从大学邮件列表中得到的。