在c++中模拟虚拟构造函数

发布于 2024-08-13 11:41:46 字数 872 浏览 7 评论 0原文

在我的应用程序中,我必须从基类派生一些类,问题是我想强制派生类具有 3 个特定的构造函数实现。由于 c++ 没有虚拟纯构造函数,它看起来非常绝望(我必须手动检查每个类的实现以确保特定的构造函数被实现,这不是很有趣)。

昨天我发现了一种疯狂的方法来模拟虚拟演员的行为:



template <class T>
class AbstractEnforcer{
  protected:
    AbstractEnforcer(){}
  private:
    static void Enforcer(){
      delete new T();
      delete new T(*(new unsigned int));
      delete new T(*(new unsigned int, *(new QString));
    }
  }

class AbstractClass : private AbstractEnforcer<AbstractClass>{

}

这种方法的唯一不便之处在于我必须使用以下语法声明所有派生类:


class X : private AbstractEnforcer<X>

即使这不是问题;因为 Enforcer() 方法永远不会被调用(即使如此它也不会执行任何操作[希望如此!!!])

我的问题是: “是否有任何方法(不使用宏)强制派生类使用此机制而不对 AbstractClass 进行参数化(因为这仅在一个派生级别中起作用”


template <class T>
class AbstractClass : private AbstractEnforcer<T>{

}

In my application I have to derive some classes from a base one, the problem is that I want to enforce the derived classed to have 3 particular constructor implementation. As c++ don't have virtual pure constructor, it seemed quite desperate (I had to check manually each class implementation to ensure that the particular ctors are implemented, not quite fun to do).

Yesterday I found a crazy way to simulate the comportment of a virtual ctor:



template <class T>
class AbstractEnforcer{
  protected:
    AbstractEnforcer(){}
  private:
    static void Enforcer(){
      delete new T();
      delete new T(*(new unsigned int));
      delete new T(*(new unsigned int, *(new QString));
    }
  }

class AbstractClass : private AbstractEnforcer<AbstractClass>{

}

the only inconvenience with this approach is that I have to to declare all derived class with the syntax:


class X : private AbstractEnforcer<X>

And even if it's not a problem; because the Enforcer() methode never get called (and even so it does nothing [hope so!!!])

My question is:
"is there any mean (not with macros) to force the derived class to use this mechanism without parametrazing the AbstractClass (because this will work in only one level of derivation"


template <class T>
class AbstractClass : private AbstractEnforcer<T>{

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

蝶…霜飞 2024-08-20 11:41:46

您的解决方案无法解决问题,因为未实例化未使用的模板化代码,因此除非您手动调用此函数,否则它将不会验证所需构造函数的存在。

您可以做的是从执行器的构造函数中调用此方法:

template <class T>
class AbstractEnforcer{
    protected:
        AbstractEnforcer(){ Enforcer(); }
    private:
        static void Enforcer(){
            delete new T();
            delete new T(*(new unsigned int));
            delete new T(*(new unsigned int, *(new QString)));
        }
        // disable:
        AbstractEnforcer (const AbstractEnforcer &enf);
};

class AbstractClass : private AbstractEnforcer<AbstractClass>{

};

int main () {
    AbstractClass c;
}

然后,编译器会抱怨 - 任务完成。

请注意,我已禁用复制构造函数,以便无法绕过该检查(通过调用不同的构造函数)。

编辑 - 非泄漏 Enforcer():[因为绝对不需要在那里使用动态分配..]

        static void Enforcer(){
            T t1();
            T t2(int(3));
            T t3(int(4), QString());
        }

Your solution does not solve the problem since templated code that isnt used is not instantiated, and thus unless you manually invoke this function - it will not verify the existence of the wanted constructors.

What you can do is have this method called from the constructor of your enforcer:

template <class T>
class AbstractEnforcer{
    protected:
        AbstractEnforcer(){ Enforcer(); }
    private:
        static void Enforcer(){
            delete new T();
            delete new T(*(new unsigned int));
            delete new T(*(new unsigned int, *(new QString)));
        }
        // disable:
        AbstractEnforcer (const AbstractEnforcer &enf);
};

class AbstractClass : private AbstractEnforcer<AbstractClass>{

};

int main () {
    AbstractClass c;
}

Then, the compiler complains - mission accomplished.

Note that I've disabled the copy constructor so that there will be no way to bypass that check (by calling a different constructor).

Edit - Non leaking Enforcer(): [As there's absolutly no need to use dynamic allocations there..]

        static void Enforcer(){
            T t1();
            T t2(int(3));
            T t3(int(4), QString());
        }
路还长,别太狂 2024-08-20 11:41:46

请参阅 C++ 常见问题解答中的此页面

我要做的是这样的:

class AbstractClass {
    public:
        virtual AbstractClass* create() const = 0;
        virtual AbstractClass* create(unsigned int) const = 0;
        virtual AbstractClass* create(unsigned int, QString) const = 0;
};

然后每个派生类将被迫重写这些函数,这应该使用不同的构造函数创建新对象。

See this page in the C++ FAQ.

What I would do is something like this:

class AbstractClass {
    public:
        virtual AbstractClass* create() const = 0;
        virtual AbstractClass* create(unsigned int) const = 0;
        virtual AbstractClass* create(unsigned int, QString) const = 0;
};

Then each of the derived classes would be forced to override these functions, which should create new objects with different constructors.

入怼 2024-08-20 11:41:46

从这个评论到一个答案,我认为你并不是真的想实现你在这里所要求的,而是一件不同的事情。我参考的评论是:

第1部分:

我知道我们不能有虚拟的
构造函数,我不想有
一、我的目的是编译器
静态代码检查会发出警报
如果我忘记实施特定的
构造函数原型。

第 2 部分:

我的项目是
像动态加载系统这样的插件和
我以某种方式强制执行演员
第三个的原型实现
政党代码。

您在问题中要求的是 1,您可以通过不同的方式强制执行它,只需阅读一些答案,或者查看元编程示例和 boost::type_traits 库。

现在,如果您真正想要的是第 2 部分:提供动态加载插件机制,那么您不需要强制执行构造函数,而是需要为插件对象和插件对象的创建提供一个通用接口。无法实例化未知(在编译时)对象的实例,这意味着您将无法从代码中调用构造函数。我建议

// Interface:
class plugin {
public:
   virtual void operation() = 0;
};
class plugin_factory {
public:
   virtual plugin* create() = 0;
   virtual plugin* create( unsigned int ) = 0;
   virtual plugin* create( unsigned int, QString const & ) = 0;
};

用户需要提供插件的实现以及创建它们的工厂。他们可能需要为他们的库实现一个入口点,以便您可以访问工厂(或者他们可以在您的系统中注册他们的工厂,否则我建议使用库来实现这些目的(boost::extension似乎是一个值得一看的地方)

From this comment to one of the answers I think that you do not really want to achieve what you are asking here, but rather a different thing. The comment I refer to is:

Part 1:

I knew that we can't have a virtual
constructor and I don't want to have
one, my purpose is to a compiler
static code checking that will alert
me if I forgot to implement a specific
constructor prototype.

Part 2:

My project is a
plugin like dynamic loading system and
I have in some way enforce the ctors
prototypes implementation of the third
party code.

What you are asking in the question is 1, and you can enforce it in different ways, just read some of the answers, or take a look at metaprogramming examples and the boost::type_traits library.

Now, if what you really want is part 2: provide a dynamic loading plugin mechanism then you do not need to enforce the constructors, but a common interface both for the plugin objects and the creation of the plugin objects. There is no way of instantiating an instance of an object of unknown (at compile time) object, and that means that you will not be able to call the constructors from your code. I would suggest

// Interface:
class plugin {
public:
   virtual void operation() = 0;
};
class plugin_factory {
public:
   virtual plugin* create() = 0;
   virtual plugin* create( unsigned int ) = 0;
   virtual plugin* create( unsigned int, QString const & ) = 0;
};

Users will need to provide the implementation of a plugin and the factory that creates them. They will probably need to implement a point of entry for their library so that you can get access to the factory (or so they can register their factory within your system, or else I would suggest using a library for these purposes (boost::extension seems like a place to look at)

痴情 2024-08-20 11:41:46

我可能只是有一个用于生成测试的模板:

template <typename T>
void enforceConstructors() {
    T t1;
    T t2(0);
    QString q;
    T t3(0, q);
}

然后在测试中的某个地方执行以下操作:

enforceConstructors<X>();
enforceConstructors<Y>();
enforceConstructors<Z>();

这些可能全部放在一起,也可能位于每个类 X、Y、Z 的单独位置。取决于您想要如何组织测试。

如果我使用的值不合适,请输入一些合适的值,或者编译该测试但不运行它。如果您没有单元测试,请获取一些单元测试,或者将以下内容添加到类中(而不是从基类继承):

#ifndef NDEBUG
    static void test() { enforceConstructors<X>(); }
#endif

通常不需要使构造函数成为抽象基类定义的接口的一部分。原因是这样的接口用于动态多态性 - 您将一个对象传递给某个函数,然后它调用它的函数。除了使用模板之外,您不能将类“传递”给函数并让它实例化该类。无论如何,模板大多在编译时强制执行它们的接口 - 如果您实例化模板并且它使用构造函数,那么构造函数必须存在。

I'd probably just have a template for generating a test:

template <typename T>
void enforceConstructors() {
    T t1;
    T t2(0);
    QString q;
    T t3(0, q);
}

Then somewhere in your tests, do:

enforceConstructors<X>();
enforceConstructors<Y>();
enforceConstructors<Z>();

Those might be all together, or in separate places for each of the classes X, Y, Z. Depends how you want to organise your tests.

If the values I used aren't suitable, either put in some values which are, or else compile that test but don't run it. If you don't have unit tests either get some, or else add the following to the class (instead of inheriting from the base class):

#ifndef NDEBUG
    static void test() { enforceConstructors<X>(); }
#endif

You don't usually need to make constructors part of an interface defined by an abstract base class. The reason is that such interfaces are for dynamic polymorphism - you pass an object to some function, and it calls functions on it. You can't "pass" a class to a function and have it instantiate the class other than with templates. Templates mostly enforce their interfaces at compile time anyway - if you instantiate the template and it uses the constructor, then the constructor has to be there.

握住我的手 2024-08-20 11:41:46

如果您忘记实现构造函数但在代码中使用它,则会出现编译错误。例如:

Base * p = new Derived( 42 );

如果未提供 Derived(int) 构造函数,将出现编译时错误 - 将不会使用 Base 构造函数。

If you forget to implement the constructor but use it in your code, you will get a compilation error. For example:

Base * p = new Derived( 42 );

will be a compile-time error if the Derived(int) constructor is not provided - the Base constructor will not be used.

究竟谁懂我的在乎 2024-08-20 11:41:46

我最终采用了这个解决方案,但没有放弃:


#ifdef NDEBUG

#ifndef ENFORCE_CTORS
#define ENFORCE_CTORS(enforcingTemplate, enforcedClass) \
  friend void enforcingCtors(){static enforcingTemplate<enforcedClass> _enforcer;}
#endif


template<class T>
      class AbstractEnforcer : T{
        public:
          explicit AbstractEnforcer(){
            T enforcedCtor0(                                     );
            T enforcedCtor1( *(new unsigned int)                 );
            T enforcedCtor2( *(new unsigned int), *(new QString) );
            T enforcedCtor3( *(new unsigned int), *(new float  ) );
          }
      };
#endif

在每个我不想强制执行的类中,我只是添加这样的内容:



class X{
  ENFORCE_CTORS(AbstractEnforcer, X);
  /*
    .....
  */
}

我没有找到任何其他方法来在类中动态注入此代码。而且我可能不清楚这次行动的最终目的(抱歉我的英语很糟糕)。

I finally adopted this solution, but not quit convienced:


#ifdef NDEBUG

#ifndef ENFORCE_CTORS
#define ENFORCE_CTORS(enforcingTemplate, enforcedClass) \
  friend void enforcingCtors(){static enforcingTemplate<enforcedClass> _enforcer;}
#endif


template<class T>
      class AbstractEnforcer : T{
        public:
          explicit AbstractEnforcer(){
            T enforcedCtor0(                                     );
            T enforcedCtor1( *(new unsigned int)                 );
            T enforcedCtor2( *(new unsigned int), *(new QString) );
            T enforcedCtor3( *(new unsigned int), *(new float  ) );
          }
      };
#endif

and in each class that I wan't to enforce I just add like this:



class X{
  ENFORCE_CTORS(AbstractEnforcer, X);
  /*
    .....
  */
}

I didn't find any other way to inject this code dynamically in a class. And I may been unclear about the final purpose of the operation (sorry for my terrible English).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文