2

I want to create an interface - an abstract class, which among others enforces derived classes (i.e. conforming to the interface) to provide a specific constructor.

Something along the lines:

class IComClient
{
public:
    virtual IComClient(int _id, TBaseCom*_com) = 0;
    virtual void task() = 0;
private:
    int id;
    TBaseCom* com;
);

Obviously, that won't work - as I read, a class can't have a pure virtual constructor - or a virtual constructor in general. I don't care about creating instances of derived classes in a polymorphic manner, I just want the compiler to protest if the derived class doesn't provide a constructor that takes these specific input parameters.

There's an answer for C# but is the situation the same in C++?

SF.
  • 13,549
  • 14
  • 71
  • 107
  • it's the same, afaik. – apple apple May 06 '19 at 14:13
  • 4
    What is the reason for wanting to do this? There may be workarounds, depending on the application. – François Andrieux May 06 '19 at 14:13
  • 2
    You will get a compiler error anyway, if you try to instantiate an object of derived class with `(int _id, TBaseCom _com)` arguments, and derived class has no such constructor. Isn't it enough? – vahancho May 06 '19 at 14:16
  • @FrançoisAndrieux: Consistent way to integrate various submitted derived classes, including generating their instances, without dwelling on quirks of their implementation when not necessary. In particular, initializing references in ctor with provided values, something not possible at a later stage. – SF. May 06 '19 at 14:24
  • 1
    @SF. You don't have that level of control on how derived types are implemented. There is no way to force a derived type to have a reference member or to force them to initialize them in a specific way. As for uniform instantiation of derived types, just act as-if every derived type is compatible. Anyone who tries to implement a derived type that isn't will certainly have compilation errors. You can use `static_assert` with [`std::is_constructible`](https://en.cppreference.com/w/cpp/types/is_constructible) if you want to provide nicer errors. – François Andrieux May 06 '19 at 14:28
  • Side note, I would not be willing to work with a system that forced me to include reference members in my types. Reference members are problematic, and should generally be avoided when possible (and much less be forced upon others). – François Andrieux May 06 '19 at 14:29
  • @FrançoisAndrieux: I wouldn't specifically *enforce* that part, but more like *enable* it. In this case the interface is more of a promise of being called in a certain way than a demand to provide it - give the opportunity to initialize reference members, if you want them. (in particular, provide the personal I/O interface which will be at the heart of the derived class, so having it as a reference member is comfortable.) The derived class can stash it whenever, but it seems calling it as if it was its own native member would be nice. – SF. May 06 '19 at 14:34

2 Answers2

1

There is no way to enforce the existence of a specific constructor for derived classes in the base class.

You can enforce the existence of a specific constructor by attempting to invoke that constructor, or using static_assert.

Something similar might be achievable not by a base class, but using a meta class... if they are accepted into the language in a future standard.

eerorika
  • 232,697
  • 12
  • 197
  • 326
0

Interfaces exist so that old code could call new code. You write an interface which provides a function, say foo(). I can write code that calls foo() now, even though no implementation of foo() exists yet. It will be able to call any future implementations of foo(), written long after I'm retired to my villa on the Bahamas.

If you proclaim that all future descendants of your class will implement a default constructor,this information is useless to me. I cannot construct instances of a class that isn't written yet! What should I or anyone else who hasn't seen a descendant of your class do with your announcement?

If there is user A who wants to create a descendant of your class, and user B who wants to instantiate A's class, then let them decide between themselves how to do this best. You are not a party in their deal.

But wait a minute, I can kinda sorta construct instances of a class that hasn't been written yet! I need to write a template, construct an object inside, and someone will instantiate it with their class. But then I just can use the default constructor, and this use will force anyone who wants to instantiate my template to implement the default constructor.

Of course you cannot force anyone to instantiate your template. If users need it, they will implement the constructor you require. If they don't need your services, you better don't tell them what to do.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • I'm simultaneously writer of the interface and user B, and I don't want to argue with user A, just take the derived class (a plugin) and plug it into the core product without hassle. – SF. May 06 '19 at 21:32
  • @SF. if users can write their plugin classes after you have released your component, which is a normal situation, then there must be some way for you to load these plugins without explicitly naming these classes. What is this way? Show your projected plugin loading interface. – n. m. could be an AI May 07 '19 at 03:07