Struct inheritance in C++ I started learning programing with C++. It runs perfectly, but I wonder what things I can improve following the principles of class inheritance, access, overwriting, virtual functions and destructors, and why.
#include &lt;iostream&gt;  // allows program to output data to the screen
using namespace std;


struct Base {
    virtual void do_something() {};
    virtual ~Base(){};

};

struct Derived1 : public Base {
    Derived1():Base(){}
    virtual void do_something() {
        std::cout &lt;&lt; &quot;Derived1!!!&quot; &lt;&lt; std::endl;
    }
    virtual~Derived1(){};
};

struct Derived2 : public Base {
   Derived2():Base(){}
    virtual void do_something() {
        std::cout &lt;&lt; &quot;Derived2!!!&quot; &lt;&lt; std::endl;
    }
    virtual ~Derived2(){};
};

// function main begins program execution
int main(int argc, const char *argv[]) {
    std::cout &lt;&lt; &quot;Welcome&quot; &lt;&lt; std::endl;

    Derived1 derived1;
    derived1.do_something();

    Derived2 derived2;
    derived2.do_something();

    return 0;

}  // end function main
Don't add meaningless comments.
#include &lt;iostream&gt;  // allows program to output data to the screen

There is a real issue with code and comment rot. So your comments should always be meaningful as you have to maintain them with the code. It is best to reserve comments to &quot;WHY&quot; you are doing something. The code will explain &quot;HOW&quot;.

Don't do this:
using namespace std;

There are definitely issues with pulling the whole standard namespace into the global namespace.
See: Why is “using namespace std;” considered bad practice?
In my opinion the best answer is the second one: sbi though the first one is good.

If Base does no real work you can make the virtual functions abstract:
struct Base {
    virtual void do_something() {};
    virtual ~Base(){};
};

// If the user should not be able to instantiate a `Base` then do this:

struct Base {
    virtual void do_something() = 0;
    virtual ~Base() {}
};


If your functions do not alter the standard behavior then don't include them:
struct Derived1 : public Base {
    Derived1():Base(){}
    virtual void do_something() {
        std::cout &lt;&lt; &quot;Derived1!!!&quot; &lt;&lt; std::endl;
    }
    virtual~Derived1(){};
};

Here the constructor and destructor are useless. Do not bother to specify them
struct Derived1 : public Base {
    virtual void do_something() {
        std::cout &lt;&lt; &quot;Derived1!!!&quot; &lt;&lt; std::endl;
    }
};


Don't use std::endl.
        std::cout &lt;&lt; &quot;Derived2!!!&quot; &lt;&lt; std::endl;

This is the major cause of C++ code running slowly. The problem is that std::endl forces the stream to flush. The stream will automatically flush when it is need and any extra flushes are likely to be inefficient (humans are bad at working out when to flush the stream).
It is better simply to use &quot;\n&quot;
        std::cout &lt;&lt; &quot;Derived2!!!&quot; &lt;&lt; &quot;\n&quot;;


From C++11 we introduced the override specifier.
In the derived class you should mark any overridden methods with it.
struct Derived1 : public Base {
    virtual void do_something() override;
};

struct Derived2 : public Base {
    virtual void do_something() override;
};

The advantage here is that if in the future somebody changes the Base class and renames or alters the virtual functions in the base the compiler will not warn you that these functions no longer align with the base class version.