Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoiding explicit constructor calls of virtual base classes

Basic question: is it possible to avoid having to explicitly call the (non-default) constructor of every virtual base class?

Background: I'm working on some type-safe C++ wrapper classes around Windows COM objects. My current approach is to have a CBaseCOMWrapper class which encapsulates an IUnknown object for reference counting. Then, I have a CCOMWrapper template class which inherits from CBaseCOMWrapper, which defines a wrapper for specific COM types (i.e. IDXGIObject, ID3D11Device, etc). Finally, separate classes inherit from these wrapper templates to provide actual/extra functionality (i.e. CDXGIObject, CD3D11Device).

For example, I have the following classes (members omitted):

class CBaseCOMWrapper { };

template<typename T> // here, T should inherit from IUnknown
class CCOMWrapper : public virtual CBaseCOMWrapper { };

class CDXGIObject : public virtual CCOMWrapper<IDXGIObject> { };

template<>
class CCOMWrapper<IDXGIAdapter> : public virtual CCOMWrapper<IDXGIObject> { };

class CDXGIAdapter : public virtual CCOMWrapper<IDXGIAdapter> { };

Here's the corresponding diagram of the type hierarchy:

Type Hierarchy

The left column is the actual objects, the middle column the thin COM wrappers, and the right column the actual COM objects. Solid arrows denote inheritance, and dashed arrows denote encapsulation.

I use template specializations of CCOMWrapper to provide the parent-child relationships in the middle.

Problem: The wrapper classes assume a non-NULL (aka valid) pointer to a COM object, so I can't have a default constructor. Because the hierarchy is full of "diamonds", much of the inheritance is virtual; this means each class's constructor must call the constructor. So, in the example above, the constructor of CDXGIAdapter must call the constructors of CCOMWrapper<IDXGIAdapter>, CDXGIObject, CCOMWrapper<IDXGIObject>, and CBaseCOMWrapper. As the hierarchy expands (i.e. ID3D11Predicate's inheritance chain is 4 "links" long), this means more constructors must be called.

Possible solution: Ideally, I'd like to use macros to generate most of the base constructor calls, but I'd have to provide the entire inheritance chain for each COM object; this would require different macros for chains of different lengths. However, the longest such length is 4 (I'm only working with DXGI, D3D11, and D2D1), so this isn't out of the question.

So how can I avoid having to call all the constructors? Alternatively, is there a better way to achieve what I'm trying to do?

like image 987
Drew McGowen Avatar asked Sep 09 '14 15:09

Drew McGowen


People also ask

Why should calls to virtual functions be avoided in constructors and destructors?

So, Don't invoke virtual functions from constructors or destructors that attempts to call into the object under construction or destruction, Because the order of construction starts from base to derived and the order of destructors starts from derived to base class.

Can constructor call virtual method?

You can call a virtual function in a constructor, but be careful. It may not do what you expect. In a constructor, the virtual call mechanism is disabled because overriding from derived classes hasn't yet happened. Objects are constructed from the base up, “base before derived”.

Why virtual constructor is not possible?

Constructor can not be virtual, because when constructor of a class is executed there is no vtable in the memory, means no virtual pointer defined yet. Hence the constructor should always be non-virtual.

Can virtual class have constructor?

In C++, the constructor cannot be virtual, because when a constructor of a class is executed there is no virtual table in the memory, means no virtual pointer defined yet. So, the constructor should always be non-virtual. But virtual destructor is possible.


1 Answers

So as it turns out, for what I want to accomplish, the CCOMWrapper template is unnecessary. I just need each class to provide a constructor that takes the corresponding COM object type:

class CDXGIObject : public CCOMObject
{
public:
    CDXGIObject(IDXGIObject *obj);
};

class CDXGIFactory : public CDXGIFactory
{
public:
    CDXGIFactory(IDXGIFactory *obj);
};

This eliminates the need for virtual inheritance, thus I don't need to call all of the base constructors anymore.

like image 178
Drew McGowen Avatar answered Sep 23 '22 08:09

Drew McGowen