Uproszczenie kodu, inicjalizacja obiektów podczas kompilacji

0

Cześć. Mam taki kod, chodzi o wykorzystanie paru obiektów (a konkretniej ich wirtualnych funkcji) z jakiejś zewnętrznej biblioteki. Mam kilkadziesiąt takich interfejsów, każda klasa jest przypisana tylko do jednego obiektu (SomeAbstractInterface -> whatever). initialize_interfaces i terminate_interfaces musi być wykonany w specyficznym momencie podczas wykonywania programu, nie mogę zrobić tego na samym początku.

I teraz pytanie, czy da się tu coś uprościć/poprawić. Docelowo chciałbym pozbyć się konieczności trzymania module_name, interface_name i all_instances w pamięci, wszystko to znane jest już w czasie kompilacji i nic się tu nie zmienia.

Mniej więcej coś takiego chciałbym otrzymać w ostatecznym kodzie:

class SomeAbstractInterface {
public:
  virtual void unknown00();
  virtual void unknown01();
  virtual void unknown02();
  virtual void unknown03();
  virtual void unknown04();
  virtual void unknown05();
};
// ...


static SomeAbstractInterface * whatever = nullptr
// ...

void initialize_interfaces() {
  whatever = find_interface("module.dll", "interface_abc");
  // ...
}

Jak coś takiego osiągnąć w jakiś sprytniejszy sposób, nie robiąc tego co w powyższym kodzie ręcznie? Tak jak wspominałem tych interfejsów jest kilkadziesiąt więc nie byłoby to zbyt czytelne/łatwe w modyfikacji.

To co teraz mam:

#include <iostream>
#include <string_view>
#include <vector>

#undef interface

void* find_interface(std::string_view module_name, std::string_view interface_name) {
  std::cout << module_name << ": " << interface_name;
  // ...
  return nullptr;
}


class BaseInterface {
public:
  BaseInterface(std::string_view _module_name, std::string_view _interface_name)
    : module_name(_module_name), interface_name(_interface_name) {
    all_instances.push_back(this);
  }

  void* pointer;
  std::string_view module_name;
  std::string_view interface_name;

  static inline std::vector<BaseInterface*> all_instances;
};


template <typename abstract_interface>
class Interface : public BaseInterface {
  using BaseInterface::BaseInterface;
public:
  abstract_interface* operator->() {
    return reinterpret_cast<abstract_interface*>(pointer);
  }
};


void initialize_interfaces() {
  for (auto interface : BaseInterface::all_instances) {
    interface->pointer = find_interface(interface->module_name, interface->interface_name);
    // ...
  }
}


void terminate_interfaces() {
  for (auto interface : BaseInterface::all_instances) {
    interface->pointer = nullptr;
    // ...
  }
}



class SomeAbstractInterface {
public:
  virtual void unknown00();
  virtual void unknown01();
  virtual void unknown02();
  virtual void unknown03();
  virtual void unknown04();
  virtual void unknown05();
};
// ...


static Interface<SomeAbstractInterface> whatever("module.dll", "interface_abc");
//...


int main(int argc, char** argv) {
  // some code
  initialize_interfaces();
  // some code
  whatever->unknown00();
  // some code
  terminate_interfaces();
  // some code

  return 0;
}
0
class SomeAbstractInterface
{
  public:
  virtual void unknown00();
  virtual void unknown01();
  virtual void unknown02();
  virtual void unknown03();
  virtual void unknown04();
  virtual void unknown05();
};

SomeAbstractInterface *get_interface()
{
  static SomeAbstractInterface *whatever=find_interface("module.dll", "interface_abc");
  return whatever;
}
1

Rozumiem, że z jakiegoś powodu nie możesz po prostu polinkować się do tych dllek i zainstancjonować obiektów normalnie? Bo to byłoby chyba najbardziej „koszerne”.

0

Co za problem pakujesz to samo do metody i masz:

class IntBase
{
    virtual SomeAbstractInterface *get_interface()=0;
};

class IntA:public IntBase
{
    virtual SomeAbstractInterface *get_interface()
    {
        static SomeAbstractInterface *whatever=find_interface("module.dll", "interface_abc");
        return whatever;
    }
};

vector<IntBase> IntList;

Ewentualnie możesz dowalić:

template<const char *dll,const char *name> class IntTemplate:public IntBase
{
    virtual SomeAbstractInterface *get_interface()
    {
        static SomeAbstractInterface *whatever=find_interface(dll,name);
        return whatever;
    }
}

Lub wyłącznie przez wzorzec:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class sai
{
  public:
  virtual void unknown03()=0;
};

class saiA:public sai
{
  public:
  virtual void unknown03() { cout<<"A.unknown03()"<<endl; }
};

class saiB:public sai
{
  public:
  virtual void unknown03() { cout<<"B.unknown03()"<<endl; }
};

sai *find_interface(const char *dll,const char *name)
{
	cout<<dll<<' '<<name<<endl;
	if(dll==string("abc")) return new saiA();
	else if(dll==string("ghi")) return new saiB();
	return nullptr;
}

class InterfaceBase
{
	public:
	virtual sai *get()=0;
	sai *operator->() { return get(); }
};

template<const char *dll,const char *name> class Interface: public InterfaceBase
{
    public:
	virtual sai *get()
	{
		static sai *intf=find_interface(dll,name);
	 	return intf; 
	}
};

constexpr char abc[]="abc";
constexpr char def[]="def";
constexpr char ghi[]="ghi";
constexpr char jkl[]="jkl";

int main()
{
	vector<InterfaceBase*> IntList;
	IntList.push_back(new Interface<abc,def>());
	IntList.push_back(new Interface<ghi,jkl>());
	for(auto intf:IntList) (*intf)->unknown03();
	for(auto intf:IntList) (*intf)->unknown03();
	for(auto intf:IntList) (*intf)->unknown03();
    return 0;
}

https://ideone.com/UlovJC
Jak widać moduł ładowany tylko raz.

1 użytkowników online, w tym zalogowanych: 0, gości: 1