Class 'Virtual' question

Started by
13 comments, last by Servant of the Lord 8 years, 1 month ago
Hi guys,

With classes and how you can override 'virtual' members with your own implementation, is it possible to also override (or add additional) public & private variables to the new class instance also?

For example class instance A might just used the default public variables and class instance B might have additional variables X,Y, & Z.

Then you could query the value of X by doing Something = B.X

Is this sort of thing possible?

Thanks in advance.
Advertisement
You are mixing up nomenclature here, making your question hard to answer.

So let's get that out of the way by making two definitions:
Type: a class, struct or simple type (int, float,...) definition
Instance: a named, usable instance of a type

Now the answer:
Types can be derived from other types, and when that happens, members can be added, overridden and hidden, but never renamed or removed.

Instances are of exactly one type and contain exactly what is defined by the type definition, not more, not less.

I hope that helps!

A small example to demonstrate it in C++ syntax:


class A {
public:
  A();

  int x;
  int z;
};

class B: public A {
public:
  B();

  int y;    // Add new variable to derived class.
  double z; // Add new variable to derived class (with a confusing name).
};




int main() {

    int i;
    A a;
    B b;

    // A is a class type.
    // B is a class type (derived from A)

    // i is an instance of built-in 'int' type.
    // a is an instance of 'A' class type.
    // b is an instance of 'B' class type.

    i = 0;      // ok

    a.x = 1;    // ok
//    a.y = 2; // error, A.y does not exist.
    a.z = 3;    // ok

    // No surprises in accessing 'a', I hope :)

    b.x = 4;    // ok (changes the 'x' defined in its base class A)
    b.y = 5;    // ok
    b.z = 6.3;  // ok (changes 'z' defined in class B)


    // So far so good, but I said "add variable" near B::z. Can you still access A::z?  Yes you can!!

    b.A::z = 4; // ok (changes 'z' defined in class A)

    return 0;
}

// So far so good, but I said "add variable" near B::z. Can you still access A::z? Yes you can!!


Good example.

Note that "can you" and "should you" are different.

There are several things you can do like this. But you generally should not do them.

Going back to the original question, it is something you can do, but probably not something you should do.

Hiding and masking things in derived classes breaks the substitution principle. The base class is no longer an abstracted form of the leaf classes, objects are no longer substitutable for each other.

Yes you can!!


Indeed, that's a case of B hiding something it inherits from A. It's not good practice because it can be rather confusing. Some compilers will emit a warning.

Thanks guys for information.

I have up-voted all answers and understand the pro's and (mainly) con's of doing such a thing now.

Thanks again :)

please note that if you do this as Alberth did, and pass each instance of class B to a function that takes an instance of class A, it will use only the members in class A. For

example:


int GetZ(const A& a)
{
    return a.z;
}

int main(int argc, char **argv)
{
   A a;
   B b;
   a.z = 52;
   b = a;
   b.z = 1.5;
   std::cout << GetZ(b) << std::endl;
   return 0;
}

will always output "52".
So I'm not even sure that doing such a thing would serve a practical purpose.

However, you can add new members, and doing so is usually the purpose in making a new class. You just can't really override the meaning of old ones.
And if you need to change how certain members are used or accessed, you can use virtual functions for that.

Yep, that would be the plan. I wouldn't use class A in this case, it would always be a derivation. So, I'd only ever use class B, C, D, etc. :)

Breaks LSP. Don't do it.

Yep, that would be the plan. I wouldn't use class A in this case, it would always be a derivation. So, I'd only ever use class B, C, D, etc.

You mean you only instantiate derived classes, right?

(makese sense, as you generally don't code a derived class if you don't use it smile.png )

However, assuming your A class has a reason for existing (otherwise making separate classes B, C, D would be better), there is code that you (indirectly) use, which does use the A instance inside your derived class instances. Your sanity is a lot better preserved if you make the derived classes a particular form of the base class (which is what inheritance is about).

The "A::z" access in C++ mostly exists because Mr Stroustrup considers it important that you can access all variables at all times. Not because it is a useful thing to do here, but if you ever run into this problem, and you cannot fix it nicely, then, as a last resort, the C++ language does give you an escape route to work around the problem for now.

My example was very much constructed. In a real case, I would move the A::z code to another derived class, rename either A::z or B::z, or make A::z a real, so I wouldn't need B::z.

C++ is a lot about giving choice to the programmer. It doesn't try to decide for you what you should or should not do. It provides functionality, and it's up to you to draw a border what you find acceptable code.

@ExErvus: What is LSP? Even Wikipedia doesn't know what it means: https://en.wikipedia.org/wiki/LSP

This topic is closed to new replies.

Advertisement