Thread: Virtual Help

  1. #1
    Registered User
    Join Date
    Jul 2019
    Posts
    34

    Virtual Help

    So I am practicing virtual and I think im geting the hang of it. I was having trouble moreso with the concept of virtual and how it works than anything else but I just made a practice project, and I would like someone to review it so I'm not making mistakes. Thanks!

    Code:
    #include<iostream>using namespace std;
    
    
    class Vehicle
    {
        public:
            virtual void Accelerate()
            { cout << "Generic Vehicle Acceleration Speed" << endl; }
    
    
            void Brake()
            { cout << "Generic vehicle Braking Speed" << endl; }
    };
    
    
    class Car : public Vehicle
    {
        public:
            void Accelerate()
            { cout << "Generic Car Class Acceleration Speed" << endl; }
    
    
            void Brake()
            { cout << "Generic Car Class Braking Speed" << endl; }
    
    
            virtual void CarHeadlightBrightness()
            { cout << "Default Brightness" << endl; }
    };
    
    
    class MonteCarlo : public Car
    {
        public:
            void Accelerate()
            { cout << "Monte Carlo Accelerating" << endl; }
    
    
            void Brake()
            { cout << "Monte Carlo Braking" << endl; }
    
    
            void CarHeadlightBrightness()
            { cout << "Medium Brightness" << endl; }
    };
    
    
    int main()
    {
        Vehicle *vehicle;
        Car *car;
        MonteCarlo monteCarlo;
        vehicle = &monteCarlo;
        car = &monteCarlo; //Use brightness function from Monte Carlo class
    
    
    
    
        //virtual function, binded at runtime
        vehicle->Accelerate();
    
    
        // Non-virtual function, binded at compile time
        vehicle->Brake();
    
    
        car->CarHeadlightBrightness();
    }

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Well first off you should be listening to your compiler, it should be generating several warning messages.

    ||=== Build: Debug in homework (compiler: gcc-8) ===|
    /main.cpp|6|warning: ‘class Vehicle’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]|
    /main.cpp|18|warning: base class ‘class Vehicle’ has accessible non-virtual destructor [-Wnon-virtual-dtor]|
    /main.cpp|18|warning: ‘class Car’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]|
    /main.cpp|34|warning: base class ‘class Car’ has accessible non-virtual destructor [-Wnon-virtual-dtor]|
    /main.cpp|34|warning: ‘class MonteCarlo’ has virtual functions and accessible non-virtual destructor [-Wnon-virtual-dtor]|
    ||=== Build finished: 0 error(s), 5 warning(s) (0 minu
    You need to fix these problems.

    Next why are you using those pointers? Your Monte Carlo class already inherited those classes so you shouldn't need those dangerous external pointers.

    Your main() should look more like (after fixing the warnings):

    Code:
    int main()
    {
        MonteCarlo monteCarlo;
    
        monteCarlo.Accelerate();
        monteCarlo.Brake();
        monteCarlo.CarHeadlightBrightness();
    }

  3. #3
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Ah, I dont see any of those warnings. I just copied the code from here, near the top:

    Virtual Function in C++ - GeeksforGeeks

    The example worked and so I changed it to my own code. When I change it to what you have, the virtual doesnt seem to work anymore, I removed virtual from the base class and it still used the monte carlo functions instead of a default. Or maybe its supposed to have the other stuff, idk i'm terrible with figuring stuff out without an example to see, which is why I looked up and copied that example.
    Last edited by ChayHawk; 07-22-2019 at 04:06 AM.

  4. #4
    Registered User
    Join Date
    May 2019
    Posts
    214
    Compiler warnings are configurable, so you may not have sufficient warning level enabled to see that one.

    The one thing that should be drilled into the mind about creating virtual base classes is that they must have a virtual destructor. Without that you can end up with derived objects that will not call their destructors appropriately (various tutorials and texts on the subject explain why, and what exceptions to the rule might apply if you're daring).

    As to @jimblumberg's other point, about avoiding the pointers, I want to point out that the code he posted would not work exactly the same as your original code. It is informative as to the operation and comparison of functions that override or hide base class functions of the same name, vs the behavior of derived classes overriding virtual base functions.

    In particular, the call to montecarlo.Brake(); would differ.

    This is because in the OP example the call is made through a 'vehicle' pointer, so the function will be vehicle's brake, while@jimblumberg's version would call Brake from the instance of montecarlo, producing different 'brake' messages.

    This is because Brake is not a virtual function in the base class.

    Indeed, the primary way in which code utilizes the power of virtual functions is through objects represented by base class pointers, though references of base class type can refer to derived types virtually, too.

    For example:

    Code:
    Vehicle &v = monteCarlo;
    
    v.Accelerate();
    v.Brake();
    If the text you're reading is much older, reactions like @jimblumberg's to raw pointer usage is from a modern C++ perspective. They're not dangerous when they're correct, and raw pointers used just for this kind of reference is harmless, especially where there is no cast performed. The exception, quite pertinent to his point, is when pointers are not initialized (which yours are)

    Code:
    Vehicle *vehicle {};
    In modern code initializes the pointer to default (nullptr). Older styles are still valid, like "Vehicle *vehicle = nullptr;"

    However, you are quickly going to move into a phase of storing objects with virtual base classes, and for that you'll be in the territory @jimblumberg is warning about. If your compiler doesn't complain, you should learn to avoid something like this:

    Code:
    Vehicle *v = new MonteCarlo();
    Which is the old style raw pointer approach, common to pre-C++11 code. Learn the use of std::unique_ptr or std::shared_ptr (and related tools) for such cases.

  5. #5
    Registered User
    Join Date
    May 2010
    Posts
    4,633
    Well your code is not the same as that code you linked to. What exactly are you trying to accomplish?

    Did you first try to understand what that code you copied is actually doing? By the way what makes you think that that code you copied is actually "good" code? Did you try to find other sites to verify that code?


    Ah, I dont see any of those warnings.
    Then you need to see about increasing your compiler warning levels, or get a better compiler.

  6. #6
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Thanks for the help guys. So I changed the code and it works. I added a virtual destructor to my base class and destructors to my other classes.

    Here is the updated code:

    Code:
    #include <iostream>#include <string>
    
    
    using namespace std;
    
    
    class Vehicle
    {
        public:
            virtual ~Vehicle(){}
    
    
            virtual void Accelerate()
            { cout << "Generic Vehicle Acceleration Speed" << endl; }
    
    
            void Brake()
            { cout << "Generic vehicle Braking Speed" << endl; }
    
    
            virtual void CarHeadlightBrightness()
            { cout << "Default Brightness" << endl; }
    };
    
    
    class Car : public Vehicle
    {
        public:
            ~Car(){}
    
    
            void Accelerate()
            { cout << "Generic Car Class Acceleration Speed" << endl; }
    
    
            void Brake()
            { cout << "Generic Car Class Braking Speed" << endl; }
    
    
            void CarHeadlightBrightness()
            { cout << "Generic Car Headlight Brightness" << endl; }
    };
    
    
    class MonteCarlo : public Car
    {
        public:
            ~MonteCarlo(){}
    
    
            void Accelerate()
            { cout << "Monte Carlo Accelerating" << endl; }
    
    
            void Brake()
            { cout << "Monte Carlo Braking" << endl; }
    
    
            void CarHeadlightBrightness()
            { cout << "Medium Brightness" << endl; }
    };
    
    
    int main()
    {
        MonteCarlo monteCarlo;
        Vehicle &v = monteCarlo;
    
    
        v.Accelerate();
        v.Brake();
        v.CarHeadlightBrightness();
    }
    Well your code is not the same as that code you linked to. What exactly are you trying to accomplish?
    Yeah, I copied it and modified it to my liking, i'm just trying to solidify how virtual works and I'm just playing around with it, but I want to make sure i'm not writing bad code in the process. I'm going to keep playign around with the virtual stuff for a couple weeks, then move on to pure virtual, etc. I havent been programming for like 7 months so i'm a little rusty.
    Last edited by ChayHawk; 07-22-2019 at 09:26 AM.

  7. #7
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Your CarHeadlightBrightness member function looked originally intended to help you figure out what happens if you add member functions in a derived class that itself ends up as a base class, but now that you moved it to the Vehicle class it is both badly named and serves no learning purpose. I would simplify:
    Code:
    #include <iostream>
    
    using namespace std;
    
    class Vehicle
    {
    public:
        virtual ~Vehicle() = default;
    
        virtual void Accelerate()
        {
            cout << "Generic Vehicle Acceleration Speed" << endl;
        }
    
        void Brake()
        {
            cout << "Generic vehicle Braking Speed" << endl;
        }
    };
    
    class Car : public Vehicle
    {
    public:
        virtual void Accelerate() override
        {
            cout << "Generic Car Class Acceleration Speed" << endl;
        }
    
        void Brake()
        {
            cout << "Generic Car Class Braking Speed" << endl;
        }
    };
    
    class MonteCarlo : public Car
    {
    public:
        virtual void Accelerate() override
        {
            cout << "Monte Carlo Accelerating" << endl;
        }
    
        void Brake()
        {
            cout << "Monte Carlo Braking" << endl;
        }
    };
    
    int main()
    {
        MonteCarlo monteCarlo;
        Vehicle& v = monteCarlo;
    
        v.Accelerate();
        v.Brake();
    }
    Notice that I removed the definitions of the destructors from the derived classes: you weren't doing anything in them, so the default ones would do. Speaking of default, I used the default keyword for the Vehicle destructor as an explicit way of saying that what would have been the implicitly-defined destructor is intended, though as virtual. Oh, and notice the use of the override keyword to ensure that you are really declaring an override rather than declaring a new virtual member function, possibly one that is an overload because of a typo error with say, the parameter list.
    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

  8. #8
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Your CarHeadlightBrightness member function looked originally intended to help you figure out what happens if you add member functions in a derived class that itself ends up as a base class, but now that you moved it to the Vehicle class it is both badly named and serves no learning purpose.
    Yeah I wasn't sure if it was "legal" to do but I did it anyways and it worked, I figured not all vehicles have headlights, like a submarine or a boat so it didn't seem appropriate to put it in the base class, i'm not sure why i moved it there, I think it was more of a mental mix up on my end.

    What would be a better name for that function? I'm going to re-add it to the car class. VehicleLights? I could create a class with that name then create sub classes of that for different light types like cabin lights, search lights, headlights, landing lights etc.

    All vehicles have lights of some kind, and I could just inherit from the classes that apply to those types of vehicles. like headlights and cabin lights for cars, landing lights for planes etc.

    Oh, and notice the use of the override keyword to ensure that you are really declaring an override rather than declaring a new virtual member function, possibly one that is an overload because of a typo error with say, the parameter list.
    I forgot what exactly override does and all my notes say is:

    -Override is a keyword that shows the reader of the code that it is a virtual method and it is overriding a virtual method of the base class.

    But I know theres more to it than that, but i'm a little confused, and i'm having trouble comprehending documentation and resources on it. So what your saying is If I have a virtual function Brake in the base class and I put Brake in the derived class, and dont declare it overridden, then the compiler will think its a new function?
    Last edited by ChayHawk; 07-23-2019 at 01:12 AM.

  9. #9
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    I updated my code, I used a pure virtual function, which I didnt want to do just yet but thats fine, it's just the one.

    Code:
    #include <iostream>
    
    using namespace std;
    
    
    class Vehicle
    {
        public:
            virtual ~Vehicle() = default;
    
    
            virtual void Accelerate()
            {
                cout << "Generic Vehicle Acceleration Speed" << endl;
            }
    
    
            virtual void Brake()
            {
                cout << "Generic vehicle Braking Speed" << endl;
            }
    
    
            virtual void Lights() = 0;
    };
    
    
    class Car : public Vehicle
    {
        public:
            virtual void Accelerate() override
            {
                cout << "Generic Car Class Acceleration Speed" << endl;
            }
    
    
            virtual void Brake() override
            {
                cout << "Generic Car Class Braking Speed" << endl;
            }
    
    
            virtual void Lights() override
            {
                cout << "Car Lights" << endl;
            }
    };
    
    
    class MonteCarlo : public Car
    {
        public:
            virtual void Accelerate() override
            {
                cout << "Monte Carlo Accelerating" << endl;
            }
    
    
            virtual void Brake() override
            {
                cout << "Monte Carlo Braking" << endl;
            }
    
    
            virtual void Lights() override
            {
                cout << "Monte Carlo Lights" << endl;
            }
    };
    
    
    int main()
    {
        MonteCarlo monteCarlo;
        Vehicle& component = monteCarlo;
        Vehicle& action = monteCarlo;
    
    
        action.Accelerate();
        action.Brake();
        component.Lights();
    }
    I gave the class objects better names, that way if im writing code and I want a component or an action I can easily select them from the context menu or memory(my memory).
    Last edited by ChayHawk; 07-23-2019 at 03:04 AM.

  10. #10
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by ChayHawk
    What would be a better name for that function? I'm going to re-add it to the car class. VehicleLights? I could create a class with that name then create sub classes of that for different light types like cabin lights, search lights, headlights, landing lights etc.

    All vehicles have lights of some kind, and I could just inherit from the classes that apply to those types of vehicles. like headlights and cabin lights for cars, landing lights for planes etc.
    Good idea, but at this point I must ask: are you done with understanding the basics of virtual functions such that you want to move on to properly modelling Vehicles and VehicleLights for some purpose? I ask because if you are just writing these classes so you can test and see how virtual vs non-virtual member functions work, what you're doing is fine. If you're trying to model properly though, then you need to start thinking about what is the point of these functions, e.g., what is the Brake function supposed to do? Why does it take no arguments and returns no value? Does it set some kind of speed member variable to 0? Likewise, what's the point of a Lights member function?
    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

  11. #11
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Yeah i'm just playing around and trying to understand virtual better, the concept of it is kind of hard for me to wrap my head around, and I just try to do the bare minimum of everything else and just focus on that one specific thing im trying to learn, in this case, virtual.

    I do want to make this a small project at some point, but adding other stuff seems to confuse me a bit so I just do the bare bones like adding text instead of actual code that is functional. Structuring classes and knowing when to use them and when to use inheritance is something i need to improve on as well, so I figured I can knock out two birds with one stone there, hence all the other classes.

  12. #12
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    So I have a question, heres my current code:

    Code:
    #include <iostream>
    
    using namespace std;
    
    
    class VehiclePart
    {
        public:
            virtual void Engine() = 0;
            virtual void Lights() = 0;
            virtual void Wheel() = 0;
    };
    
    
    
    
    class Vehicle : public VehiclePart
    {
        public:
            virtual ~Vehicle() = default;
    
    
            virtual void Accelerate() = 0;
            virtual void Decelerate() = 0;
    };
    
    
    class Automobile : public Vehicle
    {
        public:
            virtual void Accelerate() override
            {
                cout << "Generic Car Class Acceleration Speed" << endl;
            }
    
    
            virtual void Decelerate() override
            {
                cout << "Generic Car Class Braking Speed" << endl;
            }
    
    
            virtual void Lights() override
            {
                cout << "Car Lights" << endl;
            }
    
    
            virtual void Engine() override
            {
                cout << "Car Engine" << endl;
            }
    
    
            virtual void Wheel()
            {
                cout << "Generic Car wheel" << endl;
            }
    };
    
    
    class MonteCarlo : public Automobile
    {
        public:
            virtual void Accelerate() override
            {
                cout << "Monte Carlo Accelerating" << endl;
            }
    
    
            virtual void Decelerate() override
            {
                cout << "Monte Carlo Braking" << endl;
            }
    
    
            virtual void Lights() override
            {
                cout << "Monte Carlo Lights" << endl;
            }
    
    
            virtual void Engine() override
            {
                cout << "v6 4.3 liter Monte Carlo Engine" << endl;
            }
    
    
            virtual void Wheel() override
            {
                cout << "Monte Carlo Wheel" << endl;
            }
    };
    
    
    int main()
    {
        MonteCarlo monteCarlo;
        Vehicle& component = monteCarlo;
        Vehicle& action = monteCarlo;
    
    
        action.Accelerate();
        action.Decelerate();
        component.Lights();
        component.Engine();
        component.Wheel();
    }
    Do I have to put code for say the vehicle parts in automobile? Does it have to be defined there? can the automobile class be left empty and instead just define the parts in the Monte Carlo class? My understanding is that initialization code is implemented in the base class, then in automobile it's more specific to that category of vehicle, then in the actual vehicle(Monte Carlo) class, the code is modified to actually work with that vehicle, so for example the base class initializes the acceleration variable to 1, the automobile class sets it to something general, like 5, then the Monte Carlo Class sets it to something specific like 4.7.
    Last edited by ChayHawk; 07-23-2019 at 04:26 PM.

  13. #13
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by ChayHawk
    Do I have to put code for say the vehicle parts in automobile? Does it have to be defined there?
    No, if a class has a pure virtual member function, then it is an abstract base class for which no objects of that class can be instantiated. If a class derived from such a class does not override all the pure virtual member functions to implement them, then it too is an abstract base class. This is a Good Thing for classes like VehiclePart, Vehicle, and Automobile.

    Note that VehiclePart should have a virtual destructor.

    By the way, Vehicle should not inherit from VehiclePart because a Vehicle is comprised of parts rather than a vehicle is a part. Also, VehiclePart itself looks like it has a wrong design: it looks like it has a bunch of derived classes declared as member function names.

    Honestly, you really aren't done with understanding virtual member functions? You're overcomplicating your program. Keep it simple when you're trying to understand some feature of a programming language. Once you understand them, then you can start applying them for more complex stuff.. but now you have four levels of a class hierarchy when you only need three at most to understand what happens when you dont override a pure virtual function, and arguably just one class inheriting from another will do since you can find out that you get an error message.

    Sometimes you might think you understand something, then you realise you're unsure. Put aside your current work to write a simple test program to understand it.

    Quote Originally Posted by ChayHawk
    My understanding is that initialization code is implemented in the base class, then in automobile it's more specific to that category of vehicle, then in the actual vehicle(Monte Carlo) class, the code is modified to actually work with that vehicle, so for example the base class initializes the acceleration variable to 1, the automobile class sets it to something general, like 5, then the Monte Carlo Class sets it to something specific like 4.7.
    Sometimes abstract base classes can be pure interfaces: they just declare virtual member functions and don't have any member variables.

    If your abstract base class has a member variable, it might provide a constructor to initialise it with an argument rather than initialising it to some bogus value like 1 or 5.

    If you want to talk about initialising an acceleration member variable, go change your code to have one.
    Last edited by laserlight; 07-23-2019 at 07:12 PM.
    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

  14. #14
    Registered User
    Join Date
    Jul 2019
    Posts
    34
    Sorry for the late reply, work and all that. I decided to just make a new project and keep it simple, then make another project with a new concept using virtual. For this project it's just purely using virtual. I plan on a series of projects using virtual like:

    1. Plain Virtual (The project Below)
    2. Virtual class with variables that actually do something
    3. Pure virtual class
    4. Pure virtual base class and a derived class that uses virtual/pure virtual

    Maybe i'm missing others that I could learn. Here is the code for #1:

    Code:
    //Virtual practice
    
    #include <iostream>
    #include <string>
    
    
    using namespace std;
    
    
    class Base
    {
        public:
            virtual ~Base() = default;
    
    
            virtual string GetName(string m_Name){ return "Defualt Name"; }
    };
    
    
    class Derived : public Base
    {
        public:
            virtual string GetName(string m_Name) override { return m_Name; }
    };
    
    
    int main()
    {
        Derived derived;
        Base& base = derived;
        Base& baseTwo = derived;
    
    
    
    
        cout << derived.GetName("New Overridden Name") << endl;
        cout << derived.GetName("Second Overridden Name") << endl;
    
    
        return 0;
    }
    It's difficult for me to grasp things sometimes, i'm more of a visual thinker and need to visualize how something works in order to understand it, and With this, I imagine one of those old time phone switchboards that a person needed to plug in to the right socket to get the call to the right person, in this case it's the program selecting the right function to use on the fly. Thats how i imaging late binding and virtual working, whereas a regular class with no virtual methods i imagine as a modern day phone system where it just goes straight to the method thats being called. Hopefully that makes some sense.
    Last edited by ChayHawk; 07-28-2019 at 06:26 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Queries regarding virtual pointer and virtual function
    By gaurav# in forum C++ Programming
    Replies: 2
    Last Post: 12-28-2016, 04:06 AM
  2. Help with virtual function and virtual inheritance
    By shaxquan in forum C++ Programming
    Replies: 2
    Last Post: 08-30-2010, 10:39 AM
  3. Pure Virtual Function - Virtual Method Table
    By u_peerless in forum C++ Programming
    Replies: 8
    Last Post: 06-07-2008, 01:19 AM
  4. Virtual functions but non-virtual destructor
    By cunnus88 in forum C++ Programming
    Replies: 4
    Last Post: 03-31-2007, 11:08 AM
  5. Virtual & Pure virtual destructors
    By BMJ in forum C++ Programming
    Replies: 61
    Last Post: 08-22-2002, 09:38 AM

Tags for this Thread