Reputation: 3364
I have some classes (most of them are abstract, with virtual inheritance):
class A{
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : virtual public A{
public:
virtual void f3() = 0;
};
class MyA : virtual public A{
public:
virtual void f1(){ ... }
virtual void f2(){ ... }
};
class MyB : virtual public B, virtual public MyA{
public:
void f3(){ ... }
};
Now I use them:
B * object = new MyB();
object->f1(); //declared in A, imp. in MyA
object->f3(); //declared in B, imp. in MyB
Everything works fine, and the code is "good" for me (I can fast switch from MyB
to YourB
with changes in 1 line only).
How much additional memory it uses, compared to the similar code listed below (same result, different structure)?
I'm not good with memory layouts/vTables, so please explain it to me in a simple way - I want to know, if my application will spend more resources (memory) and if the executable will be slower?
And I compare that code to that one:
class MyA{
public:
virtual void f1(){ ... }
virtual void f2(){ ... }
};
class MyB : public MyA{
public:
void f3(){ ... }
};
MyB * object = new MyB();
object->f1(); //declared in MyA, imp. in MyA
object->f3(); //declared in MyB, imp. in MyB
The sizeof(object)
returns 4 in both examples (Win x32, Visual Studio native compiler), but I'm not sure if it's authoritative here. Maybe it doesn't count something - I don't think that both samples are 100% equal.
Upvotes: 0
Views: 1291
Reputation: 254431
It depends on the implementation, but typically virtual inheritance will need:
B*
to A*
will depend on which other subobjects in the same object also derive virtually from A
. I think this can be stored in the vtable, rather than the object itself, so that the overhead could be per-class rather than per-object.For memory usage, you can measure the per-object overhead in your implementation by printing sizeof (MyB)
. Any per-class overhead will probably be negligible, unless you have a huge number of classes.
Upvotes: 2
Reputation: 7625
For commonly used compilers, the overhead will be roughly as following
sizeof(object)
returns 4 in both case because you are measuring size of pointer to object, not object itself. Pointer size is same no matter to which object it points.
Upvotes: 1
Reputation: 57678
Before I start, your concern is known as a premature optimization. There are other concerns to worry about before size and space: correctness and robustness.
Inheritance is usually implement through Virtual Function Tables, in essence, a table of addresses to functions. So the amount of extra code space depends on the quantity of virtual functions.
Virtual functions are executed using a jump table. A common practice is to load the Program Counter with the value in the Function Table. This is usually 2 assembly instructions.
The amount of variable space for the function table may be less than the memory wasted by alignment padding in a structure. The wasted execution time is less than the overhead to call a function.
Edit 1:
BTW, assembly instructions are usually executed in 1 microsecond or less. So calling through a function table would take 2 microseconds. Compare this with waiting for disk I/O or User I/O.
This is why it is a premature optimization: optimizing before profiling. Profile the entire code and attend to the bottlenecks before worrying about this waste of code and variable space.
Upvotes: 2