1

Given a function with parameter x of a parent class A and class B the child class which inherits from A, how is the proper way to access the attribute of x when it is a B object? The previous description is exampled below.

-- Edit --

class A {
}

class B : public A {
    public:
      int foo;
}

void bar(A foo_){
    cout << foo_.foo << endl;
}

int main(){
    // Previous code:
    // A a{};
    // bar(a);

    // Current code:
    B b{};  // @O'Neil: B b(); will lead to the most vexing parse problem
    bar(b);
}

-- Edit --

I thank sincerely for the help.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Bruno Peixoto
  • 211
  • 1
  • 4
  • 17
  • Your code doesn't seem to match your description. Should `foo` be inside `class A` instead of `class B`? Additionally, `foo` is private in `B`, since you haven't specified `public` within the class. – John Ilacqua Aug 09 '18 at 01:37
  • Sorry, inheritance really confused me a bit. And the issue of variable access is not discussed here but I will edit it to make it clearer than without it. – Bruno Peixoto Aug 09 '18 at 01:40
  • 2
    Possible duplicate of [What is object slicing?](https://stackoverflow.com/questions/274626/what-is-object-slicing) – 1201ProgramAlarm Aug 09 '18 at 01:42

3 Answers3

1

If you pass b into bar() without changing anything else, bar() can only access the A within its parameter, a problem known as Object Slicing.

The solution is to pass b into bar() either by reference or via a pointer, even though the parameter is of type A you can use a dynamic_cast<> to try and get back to the derived object.

Pass it in as follows:

bar(&b);

and rewrite bar like this:

void bar(A *foo_)
{
    B *foo_as_B = dynamic_cast<B *>(foo_);
    if (foo_as_B != nullptr)
    {
        cout << foo_as_B->foo << endl;
    }
}

Then it'll work.

dynamic_cast<> is capable of casting a pointer/reference to a superclass into a pointer/reference to a subclass, provided the superclass object actually was originally instantiated as the subclass. It's actually a bit more complex than this, but just for getting started that will be sufficient.

In the pointer case, if the cast is OK, you get a valid pointer. If the cast can't be done, the pointer version returns nullptr. Hence the reason for checking it before using it.

Good defensive coding says you should always check pointers from unknown sources. Even though you may believe that the cast will succeed and you may be right at the time you write bar(), in production code, it's entirely possible that some other programmer will come along two or three years later and add the following:

class C : public A
{
    ....
}

C c{};
bar(&c);

At which point your check for nullptr will save you from the demon of undefined behavior.

You can also do it with references, but the failure case here is different: it throws an exception, which you'd probably want to catch.

This question shows the details of this.

-- Edit --

In response to the notes about getting error C2683: 'dynamic_cast': 'A' is not a polymorphic type, this SO Question explains why. The standard states that there must be at least one virtual function for dynamic_cast<> to work, that's what being polymorphic means.

I have never bumped into this because it's a reflex action now for me to make all destructors virtual in production code. The issue of why you want to make destructors virtual is a whole separate topic which I am not going to dig into here. Suffice it to say that it does have its advantages to do so.

All that said, the fix is to change class A as follows:

class A
{
public:
    virtual ~A() {}
};
dgnuff
  • 3,195
  • 2
  • 18
  • 32
0

According to this link, it should have been worked from a base to a derived pointer of polymorphic class and it does belongs to RTTI, but still stumbling on errors.

Bruno Peixoto
  • 211
  • 1
  • 4
  • 17
0

The final solution for the thread may be found here. Thanks for all the participants.

Bruno Peixoto
  • 211
  • 1
  • 4
  • 17