Thread: Accessing derived class functions through pointer of base class

  1. #1
    Registered User
    Join Date
    Dec 2015
    Posts
    22

    Accessing derived class functions through pointer of base class

    First of all, I know that you can't access a derived class' functions through a pointer to a base class, so I assume there is some way around this issue because right now nothing makes sense to me anymore.

    So,

    I have an abstract base class A and two classes B and C whom inherit from this base class.

    The base class has a pure virtual function called getInfo() that is meant to get the info from the objects of the derived classes.

    So in my main I have

    Code:
    int main(){
        A *arr[4];
    
    
        arr[0] = new B("Lam1", 5, "blank lack");
        arr[1] = new C("Tra1", 25, "blank lack");
        arr[2] = new C("Tra2", 35, "blank lack");
        arr[3] = new B("Lam2", 12, "blank lack");
    
    
        for (int i = 0; i < 4; i++)
        {
            cout << arr[i]->getInfo() << endl << endl;
        }
    
    
        system("pause");
    
    
        for (int i = 0; i < 4; i++)
        {
            if (dynamic_cast <B*>(arr[i]) != nullptr)
            {
                cout << arr[i]->getInfo() << endl;
            }
        }
    
    
        system("pause");
    
    
        for (int i = 0; i < 4; i++) {
    
    
            if (dynamic_cast <C*>(arr[i]) != nullptr)
            {
                            //I want to access the current object's method and change its value, i.e setValue()
                cout << arr[i]->getInfo() << endl << endl;
            }
        }
        return 0;
    }

    The comment in the bottom of the code shows where my problem lies. What do I need to do to access the object's methods without the use of virtual functions? Or do I have to? Should I be declaring the array or the objects differently?

    I must be missing something because what's the point of using inheritance if you'll need a virtual copy of each derived class' functions to get it to work properly?

    Any help appreciated.

    If you need to see any other code i.e. classes just ask but it doesnt seem to me like that's where the problem lies.

    Regards, E. Finoli

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Ideally, your base class(es) would provide the necessary interface that base classes override, so that you do not need to worry about the underlying type of the object: just invoke the virtual function and the respective derived class virtual function will be called.

    However, sometimes it may simply be that you have a special case such that you want to check if the underlying object is of a particular derived class type, and hence do something that is not part of the base class interface. Fine, use dynamic_cast.

    But this looks really bad:
    Code:
    for (int i = 0; i < 4; i++)
    {
        if (dynamic_cast <B*>(arr[i]) != nullptr)
        {
            cout << arr[i]->getInfo() << endl;
        }
    }
    
    for (int i = 0; i < 4; i++) {
        if (dynamic_cast <C*>(arr[i]) != nullptr)
        {
            //I want to access the current object's method and change its value, i.e setValue()
            cout << arr[i]->getInfo() << endl << endl;
        }
    }
    Why bother having an array of base class pointers in the first place? Why not have an array of B and another array of C? After all, you are not actually making use of polymorphism, so all these repeated dynamic_cast is just making your code inefficient and harder to read. Oh, and then you can freely call setValue since you will actually be dealing with a C object for sure.

    Quote Originally Posted by Finoli
    I must be missing something because what's the point of using inheritance if you'll need a virtual copy of each derived class' functions to get it to work properly?
    If you are not using polymorphism, then the only point to inheritance is to inherit implementation, but then you should consider if it is better to extend the interface, use composition, or maybe use private inheritance.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Quote Originally Posted by laserlight View Post
    Ideally, your base class(es) would provide the necessary interface that base classes override, so that you do not need to worry about the underlying type of the object: just invoke the virtual function and the respective derived class virtual function will be called.

    However, sometimes it may simply be that you have a special case such that you want to check if the underlying object is of a particular derived class type, and hence do something that is not part of the base class interface. Fine, use dynamic_cast.

    But this looks really bad:
    Code:
    for (int i = 0; i < 4; i++)
    {
        if (dynamic_cast <B*>(arr[i]) != nullptr)
        {
            cout << arr[i]->getInfo() << endl;
        }
    }
    
    for (int i = 0; i < 4; i++) {
        if (dynamic_cast <C*>(arr[i]) != nullptr)
        {
            //I want to access the current object's method and change its value, i.e setValue()
            cout << arr[i]->getInfo() << endl << endl;
        }
    }
    Why bother having an array of base class pointers in the first place? Why not have an array of B and another array of C? After all, you are not actually making use of polymorphism, so all these repeated dynamic_cast is just making your code inefficient and harder to read. Oh, and then you can freely call setValue since you will actually be dealing with a C object for sure.


    If you are not using polymorphism, then the only point to inheritance is to inherit implementation, but then you should consider if it is better to extend the interface, use composition, or maybe use private inheritance.
    The reason I'm using an array of base class pointers is because my assignment says to do it. Then it wants me to assign 2 of each subclass to the array, present all of them, then present only the B objects, and finally, change the value of the C objects and then present those.

    How would you do it? Simply add pure virtuals in the base class and call through the pointer?

  4. #4
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Finoli
    The reason I'm using an array of base class pointers is because my assignment says to do it. Then it wants me to assign 2 of each subclass to the array, present all of them, then present only the B objects, and finally, change the value of the C objects and then present those.

    How would you do it? Simply add pure virtuals in the base class and call through the pointer?
    Ah. The requirement means that polymorphism is intended, hence virtual functions should be used.

    How I would do this is probably by implementing the Visitor pattern. However, I suspect that implementing the Visitor pattern is beyond the scope of your exercise. If so, go ahead with what you did with dynamic_cast in the loop to check for B and C. For C, what you are missing is that you should have assigned the result of dynamic_cast:
    Code:
    auto result = dynamic_cast<C*>(arr[i]);
    if (result)
    {
        result->setValue(whatever);
    }
    Alternatively, you could be silly and yet technically correct by providing virtual functions in the base class that are aware of B and C and yet do nothing, only to be implemented in B or C respectively. For example:
    Code:
    class A
    {
    public:
        virtual ~A() = default;
        virtual void print(std::ostream& out) const;
        virtual void printIfB(std::ostream& out) const;
        virtual bool setValueIfC(X x) const;
    };
    But in practice this is bad because the base class should not "know" about derived classes, otherwise you have to modify the base class whenever you add a new derived class. The Visitor pattern avoids this (and all the dynamic_cast) by creating a parallel hierarchy, but the trade-off is that the base class of this parallel hierarchy has to be modified whenever there's a new derived class that needs to be visited.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  5. #5
    Registered User
    Join Date
    Dec 2015
    Posts
    22
    Quote Originally Posted by laserlight View Post
    Ah. The requirement means that polymorphism is intended, hence virtual functions should be used.

    How I would do this is probably by implementing the Visitor pattern. However, I suspect that implementing the Visitor pattern is beyond the scope of your exercise. If so, go ahead with what you did with dynamic_cast in the loop to check for B and C. For C, what you are missing is that you should have assigned the result of dynamic_cast:
    Code:
    auto result = dynamic_cast<C*>(arr[i]);
    if (result)
    {
        result->setValue(whatever);
    }
    Alternatively, you could be silly and yet technically correct by providing virtual functions in the base class that are aware of B and C and yet do nothing, only to be implemented in B or C respectively. For example:
    Code:
    class A
    {
    public:
        virtual ~A() = default;
        virtual void print(std::ostream& out) const;
        virtual void printIfB(std::ostream& out) const;
        virtual bool setValueIfC(X x) const;
    };
    But in practice this is bad because the base class should not "know" about derived classes, otherwise you have to modify the base class whenever you add a new derived class. The Visitor pattern avoids this (and all the dynamic_cast) by creating a parallel hierarchy, but the trade-off is that the base class of this parallel hierarchy has to be modified whenever there's a new derived class that needs to be visited.
    Alright, I tried assigning the dynamic_cast to result like you did and that worked without a problem. I do however understand that needing to cast every time you need to access a derived method is bad.
    Also, I'm not sure why accessing the method through result works. If you dont mind an explanation of what's going on underneath would be very appreciated!

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by Finoli
    I'm not sure why accessing the method through result works.
    Recall that dynamic_cast<C*> returns a pointer to the C object if it really is a C object, otherwise it returns a null pointer. So, you have a pointer to a C object, hence you can use it just as if you had written:
    Code:
    C c;
    C* p = &c;
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Just to add, when you try to call a function on an object, the compiler looks at the type of the object and sees if the function is "there" or not.
    So even if you create a C and place it in a A*, the compiler only sees the functions in A (because the type is A*), not C, because the compiler looks at the compile time (where it sees A*) and the fact that there's a C stored in there won't be known until runtime. So you can't call C's functions directly from a pointer to A. dynamic_cast<C*> returns a C* type, which makes the compiler see all C functions (because the return type is C*, the compiler sees all C's functions), hence allowing you to call them.
    (Of course, if there really isn't a C object stored in the pointer, you get null, but that doesn't change the cast's return type. The compiler works with types - if you get a null, it will compile, but most likely crash at runtime.)
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 4
    Last Post: 01-24-2016, 05:02 AM
  2. base class pointer pointing at derived class
    By mynickmynick in forum C++ Programming
    Replies: 11
    Last Post: 12-01-2008, 12:26 PM
  3. Base-class pointer, accessing object from derived class
    By Korhedron in forum C++ Programming
    Replies: 15
    Last Post: 09-28-2008, 05:30 AM
  4. finding derived class type of a pointer to a base class
    By LinuxCoder in forum C++ Programming
    Replies: 15
    Last Post: 04-10-2006, 11:08 AM
  5. base class pointer to derived class objects
    By curlious in forum C++ Programming
    Replies: 4
    Last Post: 09-28-2003, 08:39 PM

Tags for this Thread