Click here to Skip to main content
15,878,852 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
In COM server with multiple interfaces, can instance of any of co-class of any of the interfaces be created as member of some class? If I try to do so, I get compiler error "C2259 : cannot instantiate abstract class due to following members : QueryInterface, AddRef ....". How this can be resolved?
Posted

If you do it in this way you have to instanciate the vtables in the final class (iPersistStream derived from base classes) example:
class iPersist : public IPersist
{
public: // IUnknown
	virtual HRESULT	__stdcall	QueryInterface(REFIID riid,void** ppv){ return E_NOINTERFACE; }
	virtual ULONG __stdcall		AddRef(){ return InterlockedIncrement(&_ref); }
	virtual ULONG __stdcall		Release(){ if(InterlockedDecrement(&_ref)) return _ref; delete this; return 0; }

public: //	IPersist
	virtual HRESULT __stdcall GetClassID(CLSID *pClassID){ if(!pClassID) return E_POINTER; memcpy(pClassID,&IID_NULL,sizeof(CLSID)); return S_OK; }

	iPersist(){ _ref=1; }
protected:
	virtual ~iPersist(){}
	long	_ref;
};

class iStream : public IStream
{
public: // IUnknown
	virtual HRESULT	__stdcall	QueryInterface(REFIID riid,void** ppv){ return E_NOINTERFACE; }
	virtual ULONG __stdcall		AddRef(){ return InterlockedIncrement(&_ref); }
	virtual ULONG __stdcall		Release(){ if(InterlockedDecrement(&_ref)) return _ref; delete this; return 0; }


public: // ISequentialStream
	virtual	HRESULT __stdcall Read(void *pv,ULONG cb,ULONG *pcbRead){ return E_NOTIMPL; }
	virtual	HRESULT __stdcall Write(const void *pv,ULONG cb,ULONG *pcbWritten){ return E_NOTIMPL; }

public: // IStream
	virtual	HRESULT __stdcall Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition){ return E_NOTIMPL; }
	virtual HRESULT __stdcall SetSize(ULARGE_INTEGER libNewSize){ return E_NOTIMPL; }
	virtual	HRESULT __stdcall CopyTo(IStream* pstm,ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead,ULARGE_INTEGER *pcbWritten){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Commit(DWORD grfCommitFlags){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Revert(){ return E_NOTIMPL; }
	virtual HRESULT __stdcall LockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType){ return E_NOTIMPL; }
	virtual HRESULT __stdcall UnlockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Stat(STATSTG* pstatstg,DWORD grfStatFlag){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Clone(IStream** ppstm){ return E_NOTIMPL; }

	HRESULT	Open(const TCHAR* file,int mode){ /* open the file*/ return _hf?S_OK:E_FAIL; }
	HRESULT	Close(){ if(_hf) CloseHandle(_hf); _hf=0; }
	
	iStream(){ _ref=1; _hf=0; }
protected:
	virtual ~iStream(){ Close(); }
	long		_ref;
	HANDLE	_hf;
};

class iPersistStream : public iPersist, public iStream
{
public: // IUnknown
	virtual HRESULT	__stdcall	QueryInterface(REFIID riid,void** ppv)
	{
		if(IID_IUnknown         ==riid) return *(IUnknown         **)ppv=(iPersist*)this,AddRef(),S_OK;
		if(IID_IPersist         ==riid) return *(IPersist         **)ppv=this,AddRef(),S_OK;
		if(IID_IStream          ==riid) return *(IStream          **)ppv=this,AddRef(),S_OK;
		if(IID_ISequentialStream==riid) return *(ISequentialStream**)ppv=this,AddRef(),S_OK;
		return E_NOINTERFACE;
	}
	virtual ULONG __stdcall		AddRef()	{ return iPersist::AddRef(); }
	virtual ULONG __stdcall		Release()	{ return iPersist::Release(); }

	iPersistStream(){}
protected:
	virtual ~iPersistStream(){}
};


otherwise you can do it in this way (instanciate once, iPersistStream2 derived from interfaces), example:
class iPersistStream2 : public IPersist, public IStream
{
public: // IUnknown
	virtual HRESULT	__stdcall	QueryInterface(REFIID riid,void** ppv)
	{
		if(IID_IUnknown         ==riid) return *(IUnknown         **)ppv=(IPersist*)this,AddRef(),S_OK;
		if(IID_IPersist         ==riid) return *(IPersist         **)ppv=this,AddRef(),S_OK;
		if(IID_IStream          ==riid) return *(IStream          **)ppv=this,AddRef(),S_OK;
		if(IID_ISequentialStream==riid) return *(ISequentialStream**)ppv=this,AddRef(),S_OK;
		return E_NOINTERFACE;
	}
	virtual ULONG __stdcall		AddRef(){ return InterlockedIncrement(&_ref); }
	virtual ULONG __stdcall		Release(){ if(InterlockedDecrement(&_ref)) return _ref; delete this; return 0; }

public: //	IPersist
	virtual HRESULT __stdcall GetClassID(CLSID *pClassID){ if(!pClassID) return E_POINTER; memcpy(pClassID,&IID_NULL,sizeof(CLSID)); return S_OK; }

public: // ISequentialStream
	virtual	HRESULT __stdcall Read(void *pv,ULONG cb,ULONG *pcbRead){ return E_NOTIMPL; }
	virtual	HRESULT __stdcall Write(const void *pv,ULONG cb,ULONG *pcbWritten){ return E_NOTIMPL; }

public: // IStream
	virtual	HRESULT __stdcall Seek(LARGE_INTEGER dlibMove,DWORD dwOrigin,ULARGE_INTEGER *plibNewPosition){ return E_NOTIMPL; }
	virtual HRESULT __stdcall SetSize(ULARGE_INTEGER libNewSize){ return E_NOTIMPL; }
	virtual	HRESULT __stdcall CopyTo(IStream* pstm,ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead,ULARGE_INTEGER *pcbWritten){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Commit(DWORD grfCommitFlags){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Revert(){ return E_NOTIMPL; }
	virtual HRESULT __stdcall LockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType){ return E_NOTIMPL; }
	virtual HRESULT __stdcall UnlockRegion(ULARGE_INTEGER libOffset,ULARGE_INTEGER cb,DWORD dwLockType){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Stat(STATSTG* pstatstg,DWORD grfStatFlag){ return E_NOTIMPL; }
	virtual HRESULT __stdcall Clone(IStream** ppstm){ return E_NOTIMPL; }

	HRESULT	Open(const TCHAR* file,int mode){ /* open the file*/ return _hf?S_OK:E_FAIL; }
	HRESULT	Close(){ if(_hf) CloseHandle(_hf); _hf=0; }

	iPersistStream2(){ _ref=1; _hf=0; }
protected:
	virtual ~iPersistStream2(){}
	long		_ref;
	HANDLE	_hf;
};
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 11-Feb-11 16:57pm    
I did not vote for your answer only because I'm lazy enough to read such a long code, sorry.
Instead I provided conceptual explanation, if you want to take a look...
Thank you.
--SA
You cannot instantiate an abstract class. You should understand which classes are abstract: those having at least one pure virtual method, which is often called abstract as well (in newer language it is typical to have the language key word abstract in one or both cases).

So, how would you imagine the instance of the abstract class? If it was allowed, the abstract method would be attempted to to call from the VMT where the address of the method is null, which would cause the exception. So, all abstract methods should be overridden to make that class non-abstract and allow instantiation. The method you mentioned are in the base class of every single COM class (because it needs to implement IUnknown).

Most COM libraries for C++ help to implement COM interface methods automatically, but you cal also do it your self. COM interfaced in C++ syntax are merely abstract classed where all members are pure virtual functions.

—SA
 
Share this answer
 
Comments
mbue 11-Feb-11 18:53pm    
I think his misunderstood is: when class A derived from IUnknown implements the function, another class B derived from A and IUnknown can/should use the functions from A. But the compiler doesn't - because the class B needs its own instantiation of IUnknown.
regards.
Sergey Alexandrovich Kryukov 11-Feb-11 21:06pm    
Thank you for this note.
What you say is very likely.

Yes, this is very delicate moment. I know exactly how it is explained based on C++ VMT. It's mainly related to related to C++ implementation of multiple inheritance (and not the case in C++/CLI). Note that in newer language (I can remember examples of Object Pascal, Delphi Pascal (as well as Free Pascal, C# and other .NET languages), this is not the case -- base-class implementations of interface functions are compiled and called correctly without implementation of them in derived classes. For this classes, interface is a separate entity (and a key word); and only weak forms of multiple inheritance is allowed (single class parent, multiple interface parents), which can server as a reasonable discipline in C++, but it depends.

I also know the different scheme of multiple inheritance where interfaces play well, but that means creation of new language (which probably does not exist -- it was a theoretical work). In this schema the difference between virtual and non-virtual base classes is not imprinted in the inheritance but is a matter of late binding (can be changed later in any level of inheritance graph).

I never liked MFC method of helping in resolution of this problem based on pre-processor (like everything based on pre-processor). I used my own schema based on helper classes and operator overloading. I'm happy I don't have to work with COM anymore. It's gradually getting obsolete and should completely die out with time...

--SA
You may store the interfaces as pointers.
:)
 
Share this answer
 
Try to use CComPtr or CComQIPtr.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900