1

My class using an interface and require the information if an interface was used on object creation:

The interface:

class IServerSetup {
  public:
    virtual void ServerSetup () = 0;
}

The class:

class MyServer : public MqC, public IServerSetup {                                                                 
  public:
    MyServer(MqS *tmpl) : MqC(tmpl) {};                                                                            

  private:
    // service to serve all incomming requests for token "HLWO"                                                    
    void MyFirstService () { 
      SendSTART();
      SendC("Hello World");                                                                                        
      SendRETURN();
    }

    // define a service as link between the token "HLWO" and the callback "MyFirstService"                         
    void ServerSetup() {                                                                                           
      ServiceCreate("HLWO", CallbackF(&MyServer::MyFirstService));                                                 
    }                                                                                                              
};                                                                                                                 

The constructor at MqC:

MqC::MqC (struct MqS *tmpl) {                                                                          
  if (tmpl && (*(int*)tmpl) != MQ_MqS_SIGNATURE) {                                                             
    throw MqCSignatureException("MqS");                                                                        
  } else {
    hdl = MqContextCreate(0, tmpl);                                                                            
    MqConfigSetSelf (hdl, this);                                                                               
    this->objInit();    <<<<<<<<<<<< This is the important part…                                                                                     
  }                                                                                                            
}

And now the objInit() should detect the interface to proper config the object…

void MqC::objInit () {

    // use "hdl->setup.Parent.fCreate" to ckeck in context was initialized
    if (hdl->setup.Parent.fCreate != NULL) return;

    hdl->setup.Parent.fCreate = MqLinkDefault;
    hdl->setup.Child.fCreate = MqLinkDefault;

    // init the server interface
    IServerSetup * const iSetup = dynamic_cast<IServerSetup*const>(this);

    if (iSetup != NULL) {
      struct ProcCallS * ptr = (struct ProcCallS *) MqSysMalloc(MQ_ERROR_PANIC, sizeof(*ptr));
      ptr->type = ProcCallS::PC_IServerSetup;
      ptr->call.ServerSetup = iSetup;
      MqConfigSetServerSetup (hdl, ProcCall, static_cast<MQ_PTR>(ptr), ProcFree, ProcCopy);
    }
    ...

To make it short… The line:

IServerSetup * const iSetup = dynamic_cast<IServerSetup*const>(this);

Does not work in a constructor (return always NULL)… So I need to call objInit() later… this is not good.

UPDATE

If I use the objInit in the toplevel constructor… This works…

→ But is there any possibility to avoid this (always repeating objInit())… And get the top level object in MqC constructor?

MyServer(MqS *tmpl) : MqC(tmpl) {                                                                              
  objInit();                                                                                                   
};                                                                                                             
Biffen
  • 6,249
  • 6
  • 28
  • 36
Andreas Otto
  • 311
  • 1
  • 10
  • 1
    Yes. What's your question? – John Zwinck Jun 15 '18 at 12:45
  • 3
    Why should it work? As far as we know, `MqC` does not inherit from `IServerSetup`. So `dynamic_cast` is invalid and returns `nullptr`. – Yksisarvinen Jun 15 '18 at 12:47
  • @Yksisarvinen oh… you are right… I need the "MyServer" class for **objInit** and NOT the **MqC** even is **MyServer** is the toplevel … hmmm – Andreas Otto Jun 15 '18 at 12:50
  • Pass an `IServerSetup*` (perhaps defaulted to nullptr) to your objInit method. – Mat Jun 15 '18 at 12:55
  • Can you use a `dynamic_cast` on `this` in a context that is called by `this`'s constructor? I feel this would be related to how `virtual` function calls don't work in that context. – François Andrieux Jun 15 '18 at 13:38

1 Answers1

1

In void MqC::objInit () *this is a MqC. MqC has no relationship to IServerSetup so trying to cast it into one will not work.

NathanOliver
  • 171,901
  • 28
  • 288
  • 402
  • To add to this: it is not necessary to dynamic_cast to a parent. static_cast is better since it will fail at compile time when the relationship doesn't exist. – eerorika Jun 15 '18 at 13:37
  • There could be a relationship if `this` actually points to a `MyServer`. Though rarely used, `dynamic_cast` can perform sideways casts. – François Andrieux Jun 15 '18 at 13:40
  • @FrançoisAndrieux Are you talking about casting `this` down to a `MyServer` and then back up to an `IServerSetup`? – NathanOliver Jun 15 '18 at 13:41
  • @NathanOliver Yes, but `dynamic_cast` should perform that operation in one step. – François Andrieux Jun 15 '18 at 13:42
  • @FrançoisAndrieux They would both have to polymorphic. YOu also ru into the issue that since this is being called in `MqC`'s constructor the `IServerSetup` has not yet been initialized and calling member functions on it is UB. – NathanOliver Jun 15 '18 at 13:45
  • @NathanOliver I agree, and those seem to be the real problems. – François Andrieux Jun 15 '18 at 13:46
  • Just to make something clear. I write a language binding for a **library** in ~10 different languages in parallel. → C (the Source), C++,CSharp,Java,Python,Tcl,Perl,go,ruby,VB,(JS)… and only the C++ has the problem finding the Interfaces at constructor… this seems a C++ limitation. – Andreas Otto Jun 15 '18 at 15:26
  • @AndreasOtto It is. C++ doesn't do more than the minimum it needs to do for performance. If you want to add more functionality you need to code it in and explicitly pay that price. It does have inheritance issues though and there are some things you just can't do because the language does not allow it. – NathanOliver Jun 15 '18 at 15:33