Only just got around to testing this. Let's see if I did it right...
Just be warned... if you read all this that's your fault
It's long!
So I have a base class Foo with 20 virtual void funcs. And then a derived Bar class that can choose to implement and override 1 or many of the Foo virtual funcs.
The basic test differences are... Varying amounts of base class functions, varying amounts of derived class functions, and varying amounts of derived class function calls.
So here's the test results and output size code:
One Foo virtual function, one Bar override and one Bar b function call.
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
};
Bar b;
void setup() {
Serial.begin(9600);
b.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage
Sketch uses 2072 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
20 Foo virtual functions, one Bar override and still one Bar b function call:
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
};
Bar b;
void setup() {
Serial.begin(9600);
b.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2072 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
20 Foo virtual functions, 20 Bar overrides, and still one Bar b function call:
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
Bar b;
void setup() {
Serial.begin(9600);
b.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2072 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
20 Foo virtual functions, 20 Bar overrides, but 20 Bar b function calls:
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
Bar b;
void setup() {
Serial.begin(9600);
b.f1();
b.f2();
b.f3();
b.f4();
b.f5();
b.f6();
b.f7();
b.f8();
b.f9();
b.f10();
b.f11();
b.f12();
b.f13();
b.f14();
b.f15();
b.f16();
b.f17();
b.f18();
b.f19();
b.f20();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2300 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
And so it seems that, at least in preliminary tests... you really do only pay for what you use. If you only use one function, it matters not how many functions are declared/defined inside either base or derived classes. Given the above the only cost is 12bytes per unique function called.
Which makes me wonder about having two derived classes as well. Let's see:
20 Foo virtual functions, 20 Bar overrides, 20 Baz overrides, One Bar b call;
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
class Baz : public Foo {
public:
void f1 () override { x = 11; }
void f2 () override { x = 12; }
void f3 () override { x = 13; }
void f4 () override { x = 14; }
void f5 () override { x = 15; }
void f6 () override { x = 16; }
void f7 () override { x = 17; }
void f8 () override { x = 18; }
void f9 () override { x = 19; }
void f10 () override { x = 110; }
void f11 () override { x = 111; }
void f12 () override { x = 112; }
void f13 () override { x = 113; }
void f14 () override { x = 114; }
void f15 () override { x = 115; }
void f16 () override { x = 116; }
void f17 () override { x = 117; }
void f18 () override { x = 118; }
void f19 () override { x = 119; }
void f20 () override { x = 120; }
};
Bar b;
Baz bz;
void setup() {
Serial.begin(9600);
b.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2072 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
/*
20 Foo virtual functions, 20 Bar overrides, 20 Baz overrides, 1 Bar b call, 1 Baz bz call.
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
class Baz : public Foo {
public:
void f1 () override { x = 11; }
void f2 () override { x = 12; }
void f3 () override { x = 13; }
void f4 () override { x = 14; }
void f5 () override { x = 15; }
void f6 () override { x = 16; }
void f7 () override { x = 17; }
void f8 () override { x = 18; }
void f9 () override { x = 19; }
void f10 () override { x = 110; }
void f11 () override { x = 111; }
void f12 () override { x = 112; }
void f13 () override { x = 113; }
void f14 () override { x = 114; }
void f15 () override { x = 115; }
void f16 () override { x = 116; }
void f17 () override { x = 117; }
void f18 () override { x = 118; }
void f19 () override { x = 119; }
void f20 () override { x = 120; }
};
Bar b;
Baz bz;
void setup() {
Serial.begin(9600);
b.f1();
bz.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2084 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
20 Foo virtual functions, 20 Bar overrides, 20 Baz overrides, 20 Bar b calls, 1 Baz bz call
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
class Baz : public Foo {
public:
void f1 () override { x = 11; }
void f2 () override { x = 12; }
void f3 () override { x = 13; }
void f4 () override { x = 14; }
void f5 () override { x = 15; }
void f6 () override { x = 16; }
void f7 () override { x = 17; }
void f8 () override { x = 18; }
void f9 () override { x = 19; }
void f10 () override { x = 110; }
void f11 () override { x = 111; }
void f12 () override { x = 112; }
void f13 () override { x = 113; }
void f14 () override { x = 114; }
void f15 () override { x = 115; }
void f16 () override { x = 116; }
void f17 () override { x = 117; }
void f18 () override { x = 118; }
void f19 () override { x = 119; }
void f20 () override { x = 120; }
};
Bar b;
Baz bz;
void setup() {
Serial.begin(9600);
b.f1();
b.f2();
b.f3();
b.f4();
b.f5();
b.f6();
b.f7();
b.f8();
b.f9();
b.f10();
b.f11();
b.f12();
b.f13();
b.f14();
b.f15();
b.f16();
b.f17();
b.f18();
b.f19();
b.f20();
bz.f1();
}
void loop() { Serial.println(x); }
/* Memory Usage
Sketch uses 2308 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
20 Foo virtual functions, 20 Bar overrides, 20 Baz overrides, 20 Bar b calls 20 Baz bz calls
volatile int x = 60;
class Foo {
public:
virtual void f1 () {}
virtual void f2 () {}
virtual void f3 () {}
virtual void f4 () {}
virtual void f5 () {}
virtual void f6 () {}
virtual void f7 () {}
virtual void f8 () {}
virtual void f9 () {}
virtual void f10 () {}
virtual void f11 () {}
virtual void f12 () {}
virtual void f13 () {}
virtual void f14 () {}
virtual void f15 () {}
virtual void f16 () {}
virtual void f17 () {}
virtual void f18 () {}
virtual void f19 () {}
virtual void f20 () {}
};
class Bar : public Foo {
public:
void f1 () override { x = 1; }
void f2 () override { x = 2; }
void f3 () override { x = 3; }
void f4 () override { x = 4; }
void f5 () override { x = 5; }
void f6 () override { x = 6; }
void f7 () override { x = 7; }
void f8 () override { x = 8; }
void f9 () override { x = 9; }
void f10 () override { x = 10; }
void f11 () override { x = 11; }
void f12 () override { x = 12; }
void f13 () override { x = 13; }
void f14 () override { x = 14; }
void f15 () override { x = 15; }
void f16 () override { x = 16; }
void f17 () override { x = 17; }
void f18 () override { x = 18; }
void f19 () override { x = 19; }
void f20 () override { x = 20; }
};
class Baz : public Foo {
public:
void f1 () override { x = 11; }
void f2 () override { x = 12; }
void f3 () override { x = 13; }
void f4 () override { x = 14; }
void f5 () override { x = 15; }
void f6 () override { x = 16; }
void f7 () override { x = 17; }
void f8 () override { x = 18; }
void f9 () override { x = 19; }
void f10 () override { x = 110; }
void f11 () override { x = 111; }
void f12 () override { x = 112; }
void f13 () override { x = 113; }
void f14 () override { x = 114; }
void f15 () override { x = 115; }
void f16 () override { x = 116; }
void f17 () override { x = 117; }
void f18 () override { x = 118; }
void f19 () override { x = 119; }
void f20 () override { x = 120; }
};
Bar b;
Baz bz;
void setup() {
Serial.begin(9600);
b.f1();
b.f2();
b.f3();
b.f4();
b.f5();
b.f6();
b.f7();
b.f8();
b.f9();
b.f10();
b.f11();
b.f12();
b.f13();
b.f14();
b.f15();
b.f16();
b.f17();
b.f18();
b.f19();
b.f20();
bz.f1();
bz.f2();
bz.f3();
bz.f4();
bz.f5();
bz.f6();
bz.f7();
bz.f8();
bz.f9();
bz.f10();
bz.f11();
bz.f12();
bz.f13();
bz.f14();
bz.f15();
bz.f16();
bz.f17();
bz.f18();
bz.f19();
bz.f20();
}
void loop() { Serial.println(x); }
/* Memory Usage:
Sketch uses 2514 bytes (0%) of program storage space. Maximum is 253952 bytes.
Global variables use 190 bytes (2%) of dynamic memory, leaving 8002 bytes for local variables. Maximum is 8192 bytes.
*/
So it looks like regardless of what's declared/defined... Using the above code... It's about 12bytes per unique used function. Although the compiler manages to slice a few off here and there with voodoo.