COM: If I change the parent of an Interface do I n

2019-07-26 07:56发布

I have been adding new functionality to a COM Interface, and from what I have read the only way to do it( and keep it backwards compatible ) is to create a new interface that inherits the old interface and add the new methods. I have tried doing this but my hierarchy is already quite complex.

Say this is how my interfaces currently are:

IBaseInterface
    |
IDerivedInterface

and I want to add some functionality to the Base Interface, and it now looks like this:

IBaseOldInterface
    |
IBaseInterface
    |
IDerivedInterface

because I have added this new functionality do i need to create a new IDerivedInterface? I have tried it the way it is at the moment and it doesn't seem to work properly for all cases.

I just want some confirmation really, and an explanation why if possible

I need to further explain what my ideal situation would be and why:

I want to add some methods to the IBaseInterface class that then all of the derived classes can use. What I thought might be possible is this:

                   IBaseOldInterface
                  /                 \
IDerivedOldInterface               IBaseNewInterface
                   \               /
                  IDerivedNewInterface

I understand that Diamond Inheritance should be avoided but they are only interfaces so I think that will be alright.

having this new structure, when a user requests one of the INewDerivedInterfaces. The query interface will return the correct Interface for that IID, whether that is the INewDerivedInterface or the IOldDerivedInterface.

4条回答
仙女界的扛把子
2楼-- · 2019-07-26 08:20

To add new functionality to IBaseInterface, you need to create a new interface, but DO NOT change your existing hierarchy at all. What you can do instead is have the class that implements IBaseInterface also implement the new interface as well, eg:

type
  IBaseInterface = interface
    ...
  end;

  IBaseInterface2 = interface(IBaseInterface)
    ...
  end;

  IDerivedInterface = interface(IBaseInterface)
    ...
  end;

  TBaseClass = class(TInterfacedObject, IBaseInterface, IBaseInterface2)
    ...
  end;

  TDerivedClass = class(TBaseClass, IDerivedInterface)
    ...
  end;

That way, any code that wants to use the new IBaseInterface2 functionality can query any IBaseInterface for that interface, and if successful then use the new functionality, eg:

var
  Base2: IBaseInterface2;
begin
  if Supports(AnyBaseOrDerivedInterfacePtr, IBaseInterface2, Base2) then
  begin
    // use Base2 as needed...
  end;
end;
查看更多
Ridiculous、
3楼-- · 2019-07-26 08:22

Adding methods to the base interface (or replacing it by another that extends it) changes the vtable layout of all derived interfaces, so indeed you need to create new derived interfaces with new IIDs.

查看更多
Summer. ? 凉城
4楼-- · 2019-07-26 08:22

There are three ways you can add new functionality to your IBaseInterface, IDerivedInterface interfaces:

  1. You add new methods to the bottom of IDerivedInterface. The newly built apps aware of these new methods will be able to use them. Earlier built apps will keep safely using old methods. You cannot add methods to IBaseInterface or reinherit it from another interface because this will shift dependent methods. From the context of your original question I have a feeling that you are changing public interfaces used by a range of external software items, and you don't want your change to cause any issues. If so, you perhaps would want to restrain from going this path, even though it looks simple and doing the job (see below why).

  2. You can derive new interface from either IBaseInterface or IDerivedInterface and newly built apps will use it. Beware of necessity to assign new IID to the new interface.

  3. You define new interface (such as INewInterface in @DavidHeffernan's above) and your COM objects implements just more interfaces. Newly built apps can query new interface and call its methods.

Item 3 above is perhaps the typical, easy and convenient way to extend the object. Item 2 makes sense only if you need to keep methods on "main" interface, e.g. for legacy clients such as VB6. Item 1 is a way to quick add stuff without modifying code too much, it does work too - the only catch is that client won't be able to safely detect whether the server is implementing old methods only, or new ones as well.

查看更多
爷的心禁止访问
5楼-- · 2019-07-26 08:26

That does not work. As you have said, to maintain compatibility, you cannot modify an already published interface. But by changing the inheritance you are modifying the interface.

So, you could add the new methods to a new subclass and then you would have this structure:

IBaseInterface
    |
IDerivedInterface
    |
IDerivedInterface2

Or perhaps what you should do is add a new interface which the implementing objects support. So, instead of using inheritance, you simply declare that you implementing class supports multiple interfaces.

In that case you would leave the existing inheritance structure alone, and have something like this:

IBaseInterface         INewInterface
    |
IDerivedInterface

and then implement the class like this:

class TMyObject: public TInterfacedObject, IDerivedInterface, INewInterface
查看更多
登录 后发表回答