-
Password Rules are Stupid
- Common rules actually weaken security.
-
Best Practice ... Not!
- This is one reason why "old" code can be touchy.
-
Wow! That was fast!
- Making the right choices in your code can have huge payoffs in speed.
-
Ctors in Chains
- Shrink your C++ code even more by chaining your constructors together.
-
Virtual Classes
- Virtual base classes: what are they good for?!
-
Practice Makes Pretty Good
- Become a master software engineer by practicing like a ninja warrior.
-
You Should Get Out More
- Maintainability is the key to software success.
-
Why You Need Me
- Seven reasons why I think you need me to work for you.
-
I Create Wealth
- Or, why this is such a great business to be in.
-
Standards in Software
- Software engineering standards are a necessary and good thing.
-
What is a Content Management System?
- $10.5 billion will be spent on them this year (2003) alone, but what are they?
-
Top 10 Benefits of a Content Management System
- So what good are they?
-
Do You Need a Blowfish?
- What is a Blowfish? Does size matter? Is it right for me? Get your questions answered here.
-
Why Not Windows?
- Don't just take my word for it ...
-
10 Attributes of a Professional Software Engineer
- A truly professional software engineer stands out from the crowd. Here's what makes them different.
-
How to Score a Startup
- Examine all these points of startup companies and see how they add up.
|
Virtual Classes
July, 2013
My apologies, dear readers, this post isn't about virtual schooling through on-line
classes. Instead, this is about the C++ keyword 'virtual' and its use in class
inheritance. Specifically, this is meant to help understand what the compiler does
with multiple references to the same base class in a complex hierarchy of base and
derived classes.
The informative and complete C++ reference web site (cppreference.com) provides a
dry explanation for "Virtual base classes" that probably pretty
much quotes the language specification:
For each distinct base class that is specified virtual , the most derived object
contains only one base class subobject of that type, even if the class appears
many times in the inheritance hierarchy (as long as it is inherited virtual
every time).
I don't dispute that explanation (for obvious reasons), but I think I can paint a
clear image of how to think about this.
When declaring a class in C++, we (the programmer) provide the details of what
is contained within objects of that type -- we create a new complex data type.
What it contains is pretty clear; it contains the elements we just typed in.
Now consider the slightly more complex case of class B being derived from class A.
By specifying that B derives from A, and then providing more details for B itself,
we can say that B contains the elements of B and an A.
struct A
{
int a;
};
// in addition to a character attribute, class B also
// contains an A class i.e. an additional integer attribute
struct B : A
{
char b;
};
So, the objects of the derived class not only contain the member elements it declares,
but also the member elements from the base class.
It would be incorrect to try to declare that B inherits from A twice:
struct B : A, A
{
char b;
}
but what if B inerited from 2 other classes, each of which derived from A themselves?
Would B then contain 2 copies of A? The use of virtual derivation influences that
answer. Consider this class hierarchy:
struct A
{
int a;
};
// "middle layer" class inheriting from A
struct X : A
{
int x;
};
struct Y : A
{
int y;
};
// now the derived class ...
struct B : X, Y
{
char b;
};
What does class B contain now? It contains 2 integers 'a', an integer 'x' and an
integer 'y' in addition to it's own character 'b'. However, if the middle layer classes
X and Y were to use virtual inheritance for base class A, then B would only contain 1
copy of A and its members. Keep in mind that only if both middle layer classes
used the virtual keyword would this consolidation take place. If only X had virtual
inheritance, then B would contain one 'virtual' copy of A and one 'non-virtual' copy of
A. If there were more middle layer classes then there would be one copy of A for all
the 'virtual' bases, and one each for each of the 'non-virtual' base instances.
The takeaway from this is to remember to use virtual inheritance in related classes that
each derive from a common base and where they, themselves, could be used as bases for
some future classes.
The problem in the above hierarchy comes when an object instance of B is referred to as
a pointer to X or Y. In those cases, the 'a' integer attribute on B won't always be the
same.
int main()
{
B *b = new B();
X *x = (X*)b; // b, x, and y are all pointing
Y *y = (Y*)b; // to the same object now
x->a = 2; // even though x and y both point to
y->a = 3; // the b object, they a's might differ
if (x->a == y->a)
cout << "we used virtual inheritance"
else
cout << "we didn't use virtual inheritance"
}
The only other thing to note is that the order of execution for constructors is also
influenced by the use of virtual inheritance: constructors for virtual base classes
are executed before constructors on non-virtual base classes.
Now, as an exercise for the reader: in the above example, which 'a' is referenced by
b->a
|