有没有办法向类中添加新方法,而不修改原始类定义(即包含类和相应的.h文件的已编译.lib),如C#的类扩展方法?
答案 0 :(得分:17)
答案 1 :(得分:11)
不,你不能在C ++中这样做。
如果你想达到这样的目的,你有两个选择,
我更喜欢代表团的做法。
答案 2 :(得分:5)
C#类扩展方法主要是语法糖。您可以使用自由函数获得相同的功能(即,具有对类的引用或常量引用的函数作为其第一个参数)。既然这对STL很有效,为什么不为你的班级?
答案 3 :(得分:3)
在C ++中,您可以使用自由函数,但有时在将多个函数嵌套在一起时,扩展方法的效果会更好。看看这个C#代码:
var r = numbers.Where(x => x > 2).Select(x => x * x);
如果我们使用自由函数在C ++中编写它,它将如下所示:
auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });
这不仅难以阅读,而且难以编写。解决这个问题的常用方法是创建所谓的pipable函数。这些函数是通过重载|
管道运算符(它实际上是或运算符)来创建的。所以上面的代码可以这样写:
auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });
这更易于阅读和书写。许多库对范围使用pipable函数,但也可以扩展到其他类。 Boost在range库中使用它,pstade oven使用它,此C ++ linq库也使用它。
如果您想编写自己的pipable函数,请解释如何执行此操作here。但是,其他库提供了功能适配器以使其更容易。 Pstade egg有一个pipable adaptor,linq提供range_extension
适配器来为范围创建一个pipable函数。
使用linq,首先只需将函数创建为函数对象,如下所示:
struct contains_t
{
template<class Range, class T>
bool operator()(Range && r, T && x) const
{ return (r | linq::find(x)) != boost::end(r); };
};
然后使用静态初始化初始化函数,如下所示:
range_extension<contains_t> contains = {};
然后你可以像这样使用你的pipable函数:
if (numbers | contains(5)) printf("We have a 5");
答案 4 :(得分:1)
一般不是。但是,如果库不创建需要您的扩展的类的实例,并且您能够修改应用程序中创建类的实例并需要扩展的所有位置,那么您可以采用以下方式:
示例:
class derivedClass: public originalClass { /* ... */};
originalClass* createOriginalClassInstance()
{
return new derivedClass();
}
这大致是如何实现Glen建议的“继承”方法。从理论的角度来看,Glen的“具有相同界面的包装类”方法也非常好,但具有稍微不同的属性,使得在您的情况下工作的可能性降低。
答案 5 :(得分:1)
有一种方法可以完成。这是通过放松你的要求一点。在C ++中,人们经常说类的接口不仅包括其成员函数,还包括所有在类上工作的函数。
也就是说,可以将类作为参数赋予的非成员函数应该被视为其接口的一部分。
例如,std::find()
或std::sort()
是std::vector
接口的一部分,即使它们不是该类的成员。
如果你接受这个定义,那么你总是可以通过添加非成员函数来扩展一个类。
答案 6 :(得分:0)
您无法将方法或数据物理地添加到二进制形式的类文件中。但是,您可以通过编写扩展类来向该类的对象添加方法和数据(功能和状态)。这不是直截了当的,需要基于元对象协议和接口的编程。你需要做很多事情才能在C ++中实现这一点,因为它不支持反射开箱即用。在这种实现中,当您通过原始类对象指针查询由新扩展类实现的接口时,元对象实现通过元类对象返回该接口指针,该元类对象用于在运行时创建的扩展类。 这是多少可定制(基于插件)的软件应用程序框架的工作原理。但是,您必须记住,它需要将许多其他MOP机制写入使用字典的所有类的实例化元对象,其中描述了对象关系,并为原始和扩展类对象提供正确的接口指针。 Dassault Systemes的CATIA V5是用这种称为CAA V5的架构编写的,您可以通过编写具有所需功能的新扩展类来扩展现有组件。
答案 7 :(得分:-2)
抱歉,没有。一旦你的代码在obj中,你就无法改变它。如果可以在VC中完成此操作,则已经支持部分类。但有一个例外,运算符方法可以使用全局函数进行扩展,非常类似于cout&lt;&lt;在STL中实施。
答案 8 :(得分:-3)
当然可以:
template <typename Ext>
class Class: public Ext { /* ... */ };
但这并不意味着它是最好的方法。