有没有一种方法可以在不修改原始类定义的情况下向类添加新方法(即编译包含类和相应的.h文件的.lib)像C#的类扩展方法一样?

有帮助吗?

解决方案

不。C++没有这样的能力。

正如其他答案中提到的,常见的解决方法是:

  • 定义一个派生类,也许用一个工厂来隐藏实际的实现类
  • 定义一个 装饰者 班级
  • 定义对类的实例进行操作的非成员函数

其他提示

不,您不能在 C++ 中执行此操作。

如果你想实现这样的目标,你有两个选择,

  • 您可以从类继承(如果这是一个选项,它可能不合法,因为该类可能尚未编写为允许继承)
  • 您可以编写自己的包装类,该包装类具有相同的接口+您的新方法,并委托给您想要扩展的包装类。

我更喜欢委托方式。

C#类扩展方法主要是语法糖。您可以使用自由函数获得相同的功能(即,具有对类的引用或常量引用的函数作为其第一个参数)。既然这对STL很有效,为什么不为你的班级?

在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在中使用它范围库,pstade 烤箱使用它,以及这个C ++ linq 库也使用它。

如果您想编写自己的pipable函数,请解释如何执行此操作此处。但是,其他库提供了功能适配器以使其更容易。 Pstade egg有一个 pipable适配器,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");

一般不会。但是,如果库没有创建需要您的扩展的类的实例,并且您能够修改应用程序中创建该类的实例并需要您的扩展的所有位置,那么您可以采用一种方法:

  • 创建一个工厂函数,在所有需要类实例的地方调用该函数并返回指向该实例的指针(google for 设计模式工厂, ...).
  • 使用所需的扩展创建派生类。
  • 使工厂函数返回您的派生类而不是原始类。

例子:


    class derivedClass: public originalClass { /* ... */};

    originalClass* createOriginalClassInstance()
    {
         return new derivedClass();
    }
  • 当然,每当您需要访问扩展时,您都需要将原始类型转换为派生类。

这大致就是如何实现Glen建议的“继承”方法。从理论角度来看,格伦的“具有相同接口的包装类”方法也非常好,但其属性略有不同,这使得它不太可能在您的情况下工作。

有一种方法可以完成。这是通过放松你的要求一点。在C ++中,人们经常说类的接口不仅包括其成员函数,还包括所有在类上工作的函数。

也就是说,可以将类作为参数赋予的非成员函数应该被视为其接口的一部分。

例如,std::find()std::sort()std::vector接口的一部分,即使它们不是该类的成员。

如果你接受这个定义,那么你总是可以通过添加非成员函数来扩展一个类。

您无法将方法或数据物理地添加到二进制形式的类文件中。但是,您可以通过编写扩展类来向该类的对象添加方法和数据(功能和状态)。这不是直截了当的,需要基于元对象协议和接口的编程。你需要做很多事情才能在C ++中实现这一点,因为它不支持反射开箱即用。在这种实现中,当您通过原始类对象指针查询新扩展类实现的接口时,元对象实现通过元类对象返回该接口指针,该元类对象用于在运行时创建的扩展类。 这是多少可定制(基于插件)的软件应用程序框架的工作原理。但是,您必须记住,它需要使用其中描述对象关系的字典为所有类编写实例化元对象,并为原始和扩展类对象提供正确的接口指针。 Dassault Systemes的CATIA V5是用这种称为CAA V5的架构编写的,您可以通过编写具有所需功能的新扩展类来扩展现有组件。

抱歉,没有。一旦你的代码在obj中,你就无法改变它。如果可以在VC中完成此操作,则已经支持部分类。但有一个例外,运算符方法可以使用全局函数进行扩展,非常类似于cout <!> lt; <!> lt;在STL中实施。

当然可以:


template <typename Ext>
class Class: public Ext { /* ... */ };

但这并不意味着它是最好的方法。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top