58

This might have been asked a million times before or might be incredibly stupid but why is it not implemented?

class A
{
      public:
             A(){ a = 5;}
             int a;
};

class B:public A
{
      public:
             B(){ a = 0.5;}
              float a;
};

int main()
{
    A * a = new B();

    cout<<a->a;
    getch();
    return 0;
}

This code will access A::a. How do I access B::a?

Bruce
  • 33,927
  • 76
  • 174
  • 262

9 Answers9

46

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.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
Josh Kelley
  • 56,064
  • 19
  • 146
  • 246
  • In this case, how can I reach the variable of an inherited class object through base class pointers? If we are talking about functions, virtualizing solves this problem, but what about variables? – Zoltán Schmidt Jul 20 '13 at 21:36
  • 1
    @ZoltánSchmidt - If you're talking about accessing member variables in a derived class that are inherited from the base class, then you can access the members as is through the base class pointers. If you're talking about member variables in a derived class that aren't in the base class, then you can't polymorphically access them through the base class (because they might not be there). If you have more questions about accessing members through base class pointers, it's probably best to post a separate question; this may get too complicated to discuss in comments. – Josh Kelley Jul 21 '13 at 00:50
  • I meant the first version. I asked it because it seemed that I had issues with it, but now it's clear that it works. – Zoltán Schmidt Jul 21 '13 at 09:51
  • 2
    -1 this doesn't answer the question because a) the typing problem occurs with virtual functions also (think int foo() -> float foo()) yet this is solved easily (the second one doesn't override) and b) a virtual variable could be implicitly encapsulated by a function call (as virtual functions are also). the only answer seems to be that the second issue would be inconvenient as the linker would need to know the difference between virtual and non virtual variables – user3125280 Jan 05 '14 at 11:41
  • @user3125280 - I'm sorry, but I don't think your reply understands the issues. (a) The int -> float example is the same as the OP's A::a and B::a example, and I do answer the question about how to access it. As you say, it doesn't override; i.e., it's not virtual at all. (b) As you say, a virtual variable could be implicitly encapsulated by a function call, but then it's no longer a variable, it's a function that looks like a variable. (Some languages call these properties.) Asking "Why doesn't C++ have properties?" may be a legitimate question, but that's not the question asked here. – Josh Kelley Jan 05 '14 at 15:20
  • @JoshKelley fair enough, read too much into the title. if i wanted to undownvote, someone would have to edit it though.. – user3125280 Jan 05 '14 at 22:06
13

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..

James Curran
  • 101,701
  • 37
  • 181
  • 258
  • 12
    the same can be said of virtual functions, which must be accessed through a look up table. yet there is no requirement that every function is virtual. virtual variables (of the same type - probably a pointer to a polymorphic object) would make perfect sense – user3125280 Jan 05 '14 at 11:34
4

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);
Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • if you declare a function with a different return type to the return type of the virtual function it is supposed to override, it doesn't override, but rather overloads. the same could be true of a virtual variable, right? – user3125280 Jan 05 '14 at 11:36
  • @user3125280 no it is ill-formed. – Johannes Schaub - litb Jan 05 '14 at 22:07
  • 1
    i meant in a theoretical sense - *if* c++ had virtual variables, they would not work with different types, but would still make sense in some situations – user3125280 Jan 05 '14 at 22:10
3

(dynamic_cast<B*>(a))->a ? Why do you need that after all? Are virtual functions not enought?

Dark
  • 195
  • 7
  • 2
    Remember to check the result of `dynamic_cast` before dereferencing it, or use `(dynamic_cast(*a)).a` which will throw if the cast fails. – Mike Seymour Jul 14 '10 at 16:29
  • 2
    It is not possible to use `dynamic_cast` for downcasting non-polymorphic classes. The class in the OP's example is not polymorphic, which means that your `dynamic_cast` will not even compile. – AnT stands with Russia Jul 14 '10 at 17:03
  • Both commenters above are right. Anyways, using dynamic_cast usually a bad choice. All polymorphic behavior should be incapsulated into virtual functions. – Dark Jul 14 '10 at 17:15
2

You can create such effect like this:

#include <iostream>

class A {
public:
    double value;

    A() {}
    virtual ~A() {}

    virtual void doSomething() {}
};

class B : public A {
public:

    void doSomething() {
        A::value = 3.14;
    }
};

int main() {
    A* a = new B();
    a->doSomething();
    std::cout << a->value << std::endl;
    delete a;
    return 0;
}

In the example above you could say that the value of A has the same effect as a virtual variable should have.

Edit: This is the actual answer to your question, but seeing your code example I noticed that you're seeking for different types in the virtual variable. You could replace double value with an union like this:

union {
    int intValue;
    float floatValue;
} value

and acces it like:

a->value.intValue = 3;
assert(a->value.floatValue == 3);

Note, for speed reasons I would avoid this.

Tim
  • 5,521
  • 8
  • 36
  • 69
2

You can downcast your variable to access B::a.

Something like:

((B*)a)->a

I think it is the same in most OO programming languages. I can't think of any one implementing virtual variables concept...

Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
2

Because according to the C standard, the offset of a field within a class or struct is required to be a compile-time constant. This also applies to when accessing base class fields.

Your example wouldn't work with virtual getters either, as the override requires the same type signature. If that was necessary, your virtual getter would have to return at algebraic type and the receiving code would have to check at run-time if it was of the expected type.

stands2reason
  • 672
  • 2
  • 7
  • 18
1

Leaving aside the argument that virtual methods should be private, virtual methods are intended as an extra layer of encapsulation (encapsulating variations in behavior). Directly accessing fields goes against encapsulation to begin with so it would be a bit hypocritical to make virtual fields. And since fields don't define behavior they merely store data, there isn't really any behavior to be virtualized. The very fact that you have a public int or float is an anti-pattern.

Cogwheel
  • 22,781
  • 4
  • 49
  • 67
1

This isn't supported by C++ because it violates the principles of encapsulation.

Your classes should expose and implement a public (possibly virtual) interface that tells class users nothing about the internal workings of your class. The interface should describe operations (and results) that the class can do at an abstract level, not as "set this variable to X".

Mark B
  • 95,107
  • 10
  • 109
  • 188