Can inheritance be used to reduce the size of compiled code in C ++?

I am working on a project for an Arduino based system (i.e. an embedded system) and have a limited amount of ROM for the code you can live in.

I have found that I need a few different types of collection classes (eg List

, Stack

, Queue

). After writing this data, I noticed that apart from the functions that make them behave differently (e.g. Add

vs Push

vs Enqueue

, Pop

vs Dequeue

), they share a lot of common functions (e.g. they have the exact same fields).

It got me thinking, if I could create a base class that would contain all the common functionality of other classes (let's call it Collection

) and other classes inherit from it, and let them only implement functionality that is different, would result in less compiled code?

I expect this to happen because child classes can reference parent implementations of common functions, but I could be wrong, so I would rather ask before I try this change.


Okay, to clarify this further, as people seem to be misinterpreting, consider these hypothetical classes:

class A
{
protected:
    int value;
public:
    void assign(int other)
    {
        this->value = other;
    }
}

class B : public A
{
public:
    void assignAdd5(int other)
    {
        this->value = other + 5;
    }
}

      

And then the code:

A a = A();
B b = B();

a.assign(4);
b.assign(4);

      

I expect to assign

refer to the same method in both cases (and thus the same compiled block of code), despite the different types, because it B

is a subclass A

. If so, classes with similar functionality, all inheriting from the same base class that implement the similarity, will generate less compiled code than creating each class to implement the function separately, because each child class will use the same function.

The information I provided about the situation that triggered this question was just background, my question is whether this has to do with any compiler, not just the one I'm using (and I totally understand that the answer might be "it's possible that some compilers do this, but not all of them do ", which is a perfectly acceptable answer).

+3


source to share


2 answers


I cannot give an unambiguous answer, but I want to share my findings. Actually I am not as easy to measure the difference as I expected. Don't take the code too seriously, I was just trying to randomly see if it had any effect ...

#include <iostream>
#define DERIVED
#define BASE_STUFF     int a,b,c,d,e,f,g,h,i,k,m,n,o,p,q,r,s,t,u,v,w,x,y,z; \
                       double foo1(int x){return x;}                        \
                       double foo2(int x){return x;}                        \
                       double foo3(int x){return x;}                        \
                       double foo4(int x){return x;}                        \
                       Base*  foo5(Base* x){return x;}                      \
                       FPTR   foo5(FPTR a,FPTR b,FPTR c){return a;}

typedef double (*FPTR)(int,int,double);

struct Base { BASE_STUFF };

#ifdef DERIVED
struct Derived : Base{double a0,a1,a2,a3,a4,a5,a6,a7;};
#endif

#ifndef DERIVED
struct Derived {
    double a0,a1,a2,a3,a4,a5,a6,a7;
    BASE_STUFF
};
#endif

int main(int argc, char *argv[])
{
    Base b;
    b.x = 1;
    std::cout << b.foo1(b.x);
    std::cout << b.foo5(&b)->foo2(b.a);
    Derived n;
    n.a0 = 2;
    std::cout << n.foo1(n.a0);
}

      

I need to check the numbers again, but to my surprise the executable was smaller in use iostream

compared to c-style prinft

.

When I compile this with (g ++ 4.9.2)

g++ main.cpp -Os -fno-exceptions -s

      



I am getting a 13.312 kB executable. And it doesn't depend on DERIVED

. However, when I compile it with

g++ main.cpp -Os -fno-exceptions

      

size is 43,549 kB. Again independent of DERIVED

.

My findings

  • My example is not suitable for measuring the difference
  • ... however, experimenting with compiler flags makes huge differences, while inheritance or not makes little difference.
  • I would not change the design in order to reduce the size of the code. Write your code so that it's easy to read, write, use and use compiler flags if you need to squeeze the kB part out of your EXE (see also here )
+1


source


Write a monolithic container that does all of this.

Inherit from him privately. Use using

to display the methods you want to display.



Several very short methods will be generated for the dtor / ctor compiler.

0


source







All Articles