0

I would like to build a simple application framework. The user is supposed to create a class derived from a base class and either use the properties and methods of the base class or override them with his own. Unfortunately, it is not at all clear to me how to instantiate a user class object from my framework library.

// library base class in appframework.hpp
class BasicApp
{
    public:
        // Initialisation
        int initApp();

        // Update is called from main loop
        int Update();

        // Handle input
        int KeyInput(u32 KeysDown, u32 KeysHeld, u32 KeysDownRepeat, u32 KeysUp);
};
// user code
#include <appframework.hpp>


class AppMain: public BasicApp
{
    // Handle input
    int KeyInput(u32 KeysDown, u32 KeysHeld, u32 KeysDownRepeat, u32 KeysUp)
    {
        if (KeysDown & KEY_A) return 1;
        return 0;
    }
};

But how will my framework know about the AppMain class? The user should be able to override existing properties and methods and add their own that they can use but that the framework ignores.

I imagine it to be similar to a Java/Kotlin app in Android Studio:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // do whatever you want here
    }
}

Are there any similar concepts in C++?

Thank you!

  • 3
    why does your framework need to know about the user class? What specifically do you want to do with it? – 463035818_is_not_an_ai Feb 14 '23 at 15:04
  • 2
    What you describe sounds like plain old inheritance. Using `virtual` methods, base class will be able to refer to child implementation or is own (if child did not provide an override) without you having to do anything. I don't know Kotlin, but `onCreate` looks like a regular constructor? – Yksisarvinen Feb 14 '23 at 15:11
  • The framework should initiate the user class and, for example, call the KeyInput method when a key is pressed. If it has been overwritten, the method of the user class should be called, if not then that of the base class. However, at the compile time of the library, I only know the defined name of the user class and that it is a derivative of the base class. – Michael Ziegler Feb 14 '23 at 15:25
  • Why does your framework need to create instances of the derived classes? (Also, you do not need to check whether functions have been overridden. Perhaps you need to read the chapters about polymorphism in your favourite C++ book.) – molbdnilo Feb 14 '23 at 15:39
  • Just so you know frameworks based inheritance have a tendency to become unwieldy (and hard to maintain). Instead of inheritance you might want to think about how you can make a library of building blocks that you can aggregate (e.g. code reuse through crtp). So instead of an App being a keyhandler, think of an app (optionally having) a keyhandler – Pepijn Kramer Feb 14 '23 at 15:44
  • I don't think it is a problem of missunderstanding inheritance, because when I compile everything together, it works as desired. Only if I split off the framework as a library, then the user class is not known to me in its entirety, I only have the name and the knowledge that it is a derivative of the base class. How else am I supposed to create an object that has overridden methods and otherwise sticks to the structure of the known base class? – Michael Ziegler Feb 14 '23 at 15:52
  • A library with building blocks could be a solution, but the idea of a framework would be lost. I am also interested in how something like this could be implemented. – Michael Ziegler Feb 14 '23 at 15:55
  • *But how will my framework know about the AppMain class?* Your framework knows about the `BasicApp` class. If the Liskov Substitution Principle is done correctly, your framework should not need to know about AppMain, it should only need to know about BasicApp. – Eljay Feb 14 '23 at 17:12
  • Sorry, no, substitution is correct, as you can easily see in the example. Because the declaration of the class derivative cannot be known in the individually compiled library at the time of compilation, since the user of the library creates it later. Without a forward declaration, which does not require an exact specification of the class (even if it is identical to the base class), it obviously does not work and such a construct does not seem to exist in C++. A simple principle that, according to experience, works quite easily in Java and Kotlin seems to be completely impossible in C++. – Michael Ziegler Feb 14 '23 at 17:49

1 Answers1

0

Simply create BasicApp with virtual method and default implementation

class BasicApp {
public:
    virtual void onCreate() {/*default*/ }
    virtual void onStop() {/*default*/ }
};

Add AppMain that inherits from BasicApp and overrides BasicApp methods. In AppMain there is no override for onStop() that means it will be default.

class AppMain : public BasicApp {
public:
    void onCreate() override {
        BasicApp::onCreate();//optional to run default aka super in Kotlin
        //add your override here
    }
};

Unlike Kotlin not calling BasicApp::onCreate() in overriden onCreate will not throw.

user10
  • 266
  • 5
  • Is there a way to declare "class AppMain : public BasicApp" as external? A not so nice solution would be to put the instantiation in the user code and give it to the framework as its base class via dynamic cast. – Michael Ziegler Feb 14 '23 at 16:21