Why doesn't C++ have virtual variables?
Solution 1:
To access B::a:
cout << static_cast<B*>(a)->a;
To explicitly access both A::a and B::a:
cout << static_cast<B*>(a)->A::a;
cout << static_cast<B*>(a)->B::a;
(dynamic_cast is sometimes better than static_cast, but it can't be used here because A and B are not polymorphic.)
As to why C++ doesn't have virtual variables: Virtual functions permit polymorphism; in other words, they let a classes of two different types be treated the same by calling code, with any differences in the internal behavior of those two classes being encapsulated within the virtual functions.
Virtual member variables wouldn't really make sense; there's no behavior to encapsulate with simply accessing a variable.
Also keep in mind that C++ is statically typed. Virtual functions let you change behavior at runtime; your example code is trying to change not only behavior but data types at runtime (A::a
is int
, B::a
is float
), and C++ doesn't work that way. If you need to accommodate different data types at runtime, you need to encapsulate those differences within virtual functions that hide the differences in data types. For example (demo code only; for real code, you'd overload operator<< instead):
class A
{
public:
A(){ a = 5;}
int a;
virtual void output_to(ostream& o) const { o << a; }
};
class B:public A
{
public:
B(){ a = 0.5;}
float a;
void output_to(ostream& o) const { o << a; }
};
Also keep in mind that making member variables public like this can break encapsulation and is generally frowned upon.
Solution 2:
By not making data public, and accessing them through virtual functions.
Consider for a moment, how what you ask for would have to be implemented. Basically, it would force any access to any data member to go through a virtual function. Remember, you are accessing data through a pointer to an A object, and class A doesn't know what you've done in class B.
In other words, we could make accessing any data member anywhere much slower -- or you could write a virtual method. Guess which C++'s designers chose..
Solution 3:
You can't do this and C++ does not support it because it breaks with fundamental C++ principles.
A float
is a different type than an int
, and name lookup as well as determining what conversions will be needed for a value assignment happens at compile time. However what is really named by a->a
including its actual type would only be known at runtime.
You can use templates to parameterize class A
template<typename T>
class A
{
public:
// see also constructor initializer lists
A(T t){ a = t; }
T a;
};
Then you can pass the type, however only at compile time for the above mentioned principle's reason.
A<int> a(5);
A<float> b(5.5f);