Why do we need virtual functions in C++?

649,682

Solution 1

Here is how I understood not just what virtual functions are, but why they're required:

Let's say you have these two classes:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

In your main function:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

So far so good, right? Animals eat generic food, cats eat rats, all without virtual.

Let's change it a little now so that eat() is called via an intermediate function (a trivial function just for this example):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

Now our main function is:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

Uh oh... we passed a Cat into func(), but it won't eat rats. Should you overload func() so it takes a Cat*? If you have to derive more animals from Animal they would all need their own func().

The solution is to make eat() from the Animal class a virtual function:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

Main:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

Done.

Solution 2

Without "virtual" you get "early binding". Which implementation of the method is used gets decided at compile time based on the type of the pointer that you call through.

With "virtual" you get "late binding". Which implementation of the method is used gets decided at run time based on the type of the pointed-to object - what it was originally constructed as. This is not necessarily what you'd think based on the type of the pointer that points to that object.

class Base
{
  public:
            void Method1 ()  {  std::cout << "Base::Method1" << std::endl;  }
    virtual void Method2 ()  {  std::cout << "Base::Method2" << std::endl;  }
};

class Derived : public Base
{
  public:
    void Method1 ()  {  std::cout << "Derived::Method1" << std::endl;  }
    void Method2 ()  {  std::cout << "Derived::Method2" << std::endl;  }
};

Base* basePtr = new Derived ();
  //  Note - constructed as Derived, but pointer stored as Base*

basePtr->Method1 ();  //  Prints "Base::Method1"
basePtr->Method2 ();  //  Prints "Derived::Method2"

EDIT - see this question.

Also - this tutorial covers early and late binding in C++.

Solution 3

You need at least 1 level of inheritance and an upcast to demonstrate it. Here is a very simple example:

class Animal
{        
    public: 
      // turn the following virtual modifier on/off to see what happens
      //virtual   
      std::string Says() { return "?"; }  
};

class Dog: public Animal
{
    public: std::string Says() { return "Woof"; }
};

void test()
{
    Dog* d = new Dog();
    Animal* a = d;       // refer to Dog instance with Animal pointer

    std::cout << d->Says();   // always Woof
    std::cout << a->Says();   // Woof or ?, depends on virtual
}

Solution 4

Virtual Functions are used to support Runtime Polymorphism.

That is, virtual keyword tells the compiler not to make the decision (of function binding) at compile time, rather postpone it for runtime".

  • You can make a function virtual by preceding the keyword virtual in its base class declaration. For example,

    class Base
    {
       virtual void func();
    }
    
  • When a Base Class has a virtual member function, any class that inherits from the Base Class can redefine the function with exactly the same prototype i.e. only functionality can be redefined, not the interface of the function.

    class Derive : public Base
    {
       void func();
    }
    
  • A Base class pointer can be used to point to Base class object as well as a Derived class object.

  • When the virtual function is called by using a Base class pointer, the compiler decides at run-time which version of the function - i.e. the Base class version or the overridden Derived class version - is to be called. This is called Runtime Polymorphism.

Solution 5

You need virtual methods for safe downcasting, simplicity, and conciseness.

That’s what virtual methods do: they downcast safely, with apparently simple and concise code, avoiding the unsafe manual casts in the more complex and verbose code that you otherwise would have.


Non-virtual method ⇒ static binding ========================================

The following code is intentionally “incorrect”. It doesn’t declare the value method as virtual, and therefore produces an unintended “wrong” result, namely 0:

#include <iostream>
using namespace std;

class Expression
{
public:
    auto value() const
        -> double
    { return 0.0; }         // This should never be invoked, really.
};

class Number
    : public Expression
{
private:
    double  number_;
    
public:
    auto value() const
        -> double
    { return number_; }     // This is OK.

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
public:
    auto value() const
        -> double
    { return a_->value() + b_->value(); }       // Uhm, bad! Very bad!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

In the line commented as “bad” the Expression::value method is called, because the statically known type (the type known at compile time) is Expression, and the value method is not virtual.


Virtual method ⇒ dynamic binding. ======================================

Declaring value as virtual in the statically known type Expression ensures that each call will check what actual type of object this is, and call the relevant implementation of value for that dynamic type:

#include <iostream>
using namespace std;

class Expression
{
public:
    virtual
    auto value() const -> double
        = 0;
};

class Number
    : public Expression
{
private:
    double  number_;
    
public:
    auto value() const -> double
        override
    { return number_; }

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
public:
    auto value() const -> double
        override
    { return a_->value() + b_->value(); }    // Dynamic binding, OK!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

Here the output is 6.86 as it should be since the virtual method is called virtually. This is also called dynamic binding of the calls. A little check is performed, finding the actual dynamic type of object, and the relevant method implementation for that dynamic type is called.

The relevant implementation is the one in the most specific (most derived) class.

Note that method implementations in derived classes here are not marked virtual, but are instead marked override. They could be marked virtual but they’re automatically virtual. The override keyword ensures that if there is not such a virtual method in some base class, then you’ll get an error (which is desirable).


The ugliness of doing this without virtual methods ==================================================

Without virtual one would have to implement some Do It Yourself version of the dynamic binding. It’s this that generally involves unsafe manual downcasting, complexity, and verbosity.

For the case of a single function, as here, it suffices to store a function pointer in the object and call via that function pointer, but even so it involves some unsafe downcasts, complexity, and verbosity, to wit:

#include <iostream>
using namespace std;

class Expression
{
protected:
    typedef auto Value_func( Expression const* ) -> double;

    Value_func* value_func_;

public:
    auto value() const
        -> double
    { return value_func_( this ); }
    
    Expression(): value_func_( nullptr ) {}     // Like a pure virtual.
};

class Number
    : public Expression
{
private:
    double  number_;
    
    static
    auto specific_value_func( Expression const* expr )
        -> double
    { return static_cast<Number const*>( expr )->number_; }

public:
    Number( double const number )
        : Expression()
        , number_( number )
    { value_func_ = &Number::specific_value_func; }
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;
    
    static
    auto specific_value_func( Expression const* expr )
        -> double
    {
        auto const p_self  = static_cast<Sum const*>( expr );
        return p_self->a_->value() + p_self->b_->value();
    }

public:
    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    { value_func_ = &Sum::specific_value_func; }
};


auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );
    
    cout << sum.value() << endl;
}

One positive way of looking at this is, if you encounter unsafe downcasting, complexity, and verbosity as above, then often a virtual method or methods can really help.

Share:
649,682
Jake Wilson
Author by

Jake Wilson

Experienced in developing tools for 3D animation, motion capture, video game and movie production, web development, Android development, responsive design, etc...

Updated on July 10, 2022

Comments

  • Jake Wilson
    Jake Wilson almost 2 years

    I'm learning C++ and I'm just getting into virtual functions.

    From what I've read (in the book and online), virtual functions are functions in the base class that you can override in derived classes.

    But earlier in the book, when learning about basic inheritance, I was able to override base functions in derived classes without using virtual.

    So what am I missing here? I know there is more to virtual functions, and it seems to be important so I want to be clear on what it is exactly. I just can't find a straightforward answer online.

    • user3530616
      user3530616 about 7 years
      This is perhaps the biggest benefit of virtual functions -- the ability to structure your code in such a way that newly derived classes will automatically work with the old code without modification!
    • Swift - Friday Pie
      Swift - Friday Pie about 6 years
      tbh, virtual functions are staple feature of OOP, for type erasure. I think, it's non-virtual methods are what is making Object Pascal and C++ special, being optimization of unnecessary big vtable and allowing POD-compatible classes. Many OOP languages expect that every method can be overriden.
    • ILCAI
      ILCAI about 6 years
      This is a good question. Indeed this virtual thing in C++ gets abstracted away in other languages like Java or PHP. In C++ you just gain a bit more control for some rare cases (Be aware of multiple inheritance or that special case of the DDOD). But why is this question posted on stackoverflow.com?
    • ceyun
      ceyun almost 5 years
      I think if you take a look at early binding-late binding and VTABLE it would be more reasonable and make sense. So there is a good explanation ( learncpp.com/cpp-tutorial/125-the-virtual-table ) here.
    • alfC
      alfC almost 5 years
      @user3530616, yes I would add "with your old code AND even with your old binaries (compiled code). This is extremely powerful, however one pays a big price for this flexibility and it is most of the time unnecessary. youtube.com/watch?v=bIhUE5uUFOA. If you can recompile and not depend on stable binaries or don't need runtime linking, there are better options that are easier to reason about. Late binding can be done with templates in other cases and it is more powerful but in other senses (mathematical or value-semantics reasoning).
    • John David
      John David over 3 years
      I'm yet to find a better tutorial than this: nrecursions.blogspot.com/2015/06/…
  • Admin
    Admin about 14 years
    I hate to contradict you, but compile-time polymorphism is still polymorphism. Even overloading non-member functions is a form of polymorphism - ad-hoc polymorphism using the terminology in your link. The difference here is between early and late binding.
  • Ross
    Ross about 14 years
    Your example says that the returned string depends on whether the function is virtual, but it doesn't say which result corresponds to virtual and which corresponds to non-virtual. Additionally, it's a little confusing as you're not using the string that's being returned.
  • Alex Martelli
    Alex Martelli about 14 years
    @Steve314, you're pedantically correct (as a fellow pedant, I approve that;-) -- editing the answer to add the missing adjective;-).
  • Sonny
    Sonny almost 12 years
    Excellent, and gets home quickly and with the use of better examples. This is however, simplistic, and the questioner should really just read the page parashift.com/c++-faq-lite/virtual-functions.html. Other folks have already pointed to this resource in SO articles linked from this thread, but I believe this is worth re-mentioning.
  • Hesham Eraqi
    Hesham Eraqi over 10 years
    With Virtual keyword: Woof. Without Virtual keyword: ?.
  • Lotus
    Lotus about 10 years
    I assume: Base* obj = new Base(); obj->Method2(); would print "Base::Method2" -- yes?
  • Admin
    Admin about 10 years
    @Lotus - yes. In that case, the pointer type matches the original type the object was constructed as, so early vs. late binding makes no difference.
  • Kenny Worden
    Kenny Worden about 9 years
    So if I'm understanding this correctly, virtual allows the subclass method to be called, even if the object is being treated as its superclass?
  • mike
    mike about 9 years
    I don't know if early and late binding are terms specificly used in the c++ community, but the correct terms are static (at compile time) and dynamic (at runtime) binding.
  • Admin
    Admin about 9 years
    @mike - "The term "late binding" dates back to at least the 1960s, where it can be found in Communications of the ACM.". Wouldn't it be nice if there was one correct word for each concept? Unfortunately, it just ain't so. The terms "early binding" and "late binding" predate C++ and even object-oriented programming, and are just as correct as the terms you use.
  • David Sánchez
    David Sánchez almost 9 years
    I would point out similar explanation in wikipedia en.wikipedia.org/wiki/Virtual_function . Any way, really good explanation.
  • Lucas Leblanc
    Lucas Leblanc almost 9 years
    @KennyWorden more specifically, the keyword allows the base class's method to be overridden. Because Cat is derived from Animal, func() accepts a Cat. However, since *xyz is an Animal pointer, and Animal->eat() has not been overridden, it presumes to use that function instead when you don't mark eat() as a virtual function.
  • curiousguy
    curiousguy over 8 years
    Late binding doesn't just make function call slower, it makes the called function unknown until run time, so optimizations across the function call can't be applied. This can change everything f.ex. in cases where value propagation removes a lot of code (think if(param1>param2) return cst; where the compiler can reduce the whole function call to a constant in some cases).
  • rexbelia
    rexbelia over 8 years
    Instead of explaining late binding through the example of an intermediary function "func", here is a more straightforward demonstration -- Animal *animal = new Animal; //Cat *cat = new Cat; Animal *cat = new Cat; animal->eat(); // outputs: "I'm eating generic food." cat->eat(); // outputs: "I'm eating generic food." Even though you're assigning the subclassed object (Cat), the method being invoked is based on the pointer type (Animal) not the type of object it is point to. This is why you need "virtual".
  • David 天宇 Wong
    David 天宇 Wong almost 8 years
    Am I the only one finding this default behavior in C++ just weird? I would have expected the code without "virtual" to work.
  • Peter Chaula
    Peter Chaula almost 8 years
    @David天宇Wong I think virtual introduces some dynamic binding vs static and yes it is weird if you 're coming from languages like Java.
  • Skynight
    Skynight over 7 years
    @David天宇Wong as Laser mentioned, consider it the way C++ notifies the base class that there may be a more specific definition in one of its derived classes
  • Abhinav Gauniyal
    Abhinav Gauniyal over 7 years
    @David天宇Wong how should it work? The func() demands that animal is passed to it. But you pass a cat, which is an animal and has animal properties. Now when you call eat(), since function knows nothing about cat, only about animal, it will display animal's eat(). But virtual calls solve this problem by defining vtables.
  • Abhinav Gauniyal
    Abhinav Gauniyal over 7 years
    @David天宇Wong there's another method too, describe two func()s, one which takes animal and the other takes cat. Now the cat functions knows that cat eats rat.
  • everythingfunctional
    everythingfunctional over 7 years
    Would you ever NOT want to use virtual then? Seems like you would have (potentially) unpredictable behavior if someone inherited from your class.
  • saolof
    saolof over 7 years
    First of all, virtual calls are much, much more expensive than regular function calls. The C++ philosophy is fast by default, so virtual calls by default are a big no-no. The second reason is that virtual calls can lead to your code breaking if you inherit a class from a library and it changes its internal implementation of a public or private method (which calls a virtual method internally) without changing the base class behaviour.
  • underscore_d
    underscore_d about 7 years
    without declaring Base class destructor as virtual; memory for Cat may not be cleaned up. It's worse than that. Deleting a derived object through a base pointer/reference is pure undefined behaviour. So, it's not just that some memory might leak. Rather, the program is ill-formed, so the compiler may transform it into anything: machine code that happens to work fine, or does nothing, or summons demons from your nose, or etc. That's why, if a program is designed in such a way that some user might delete a derived instance through a base reference, the base must have a virtual destructor
  • underscore_d
    underscore_d about 7 years
    the run-time is aware of the three methods and expects them to be implemented As they are pure virtual, there is no way to create an instance of IUnknown, and so all subclasses must implement all such methods in order to merely compile. There's no danger of not implementing them and only finding that out at runtime (but obviously one can wrongly implement them, of course!). And wow, today I learned Windows #defines a macro with the word interface, presumably because their users can't just (A) see the prefix I in the name or (B) look at the class to see it's an interface. Ugh
  • BJovke
    BJovke almost 7 years
    Base* obj = new Derived (); This is not how it's supposed to be done in C++ and in C++11 this would produce compiler error. Pointer to Derived should always be pointer to Derived. You should never assign pointer to one object type to pointer to different object type, this programming style should be avoided. However, if you have no other option then explicit cast should be used.
  • BJovke
    BJovke almost 7 years
    void func(Animal *xyz) { xyz->eat(); } Giving this function a pointer to Cat as an argument will in modern C++ produce a compiler error. It's not the way it should be done generally in C++. The purpose of the virtual functions is to change behavior of the base class, methods of class Animal calling member method eat() will call the Animal's eat().
  • Admin
    Admin almost 7 years
    @BJovke - this answer was written before C++11 was published. Even so, I just compiled it in GCC 6.3.0 (using C++14 by default) with no problems - obviously wrapping the variable declaration and calls in a main function etc. Pointer-to-derived implicitly casts to pointer-to-base (more specialized implicitly casts to more general). Visa-versa you need an explicit cast, usually a dynamic_cast. Anything else - very prone to undefined behavior so make sure you know what you're doing. To the best of my knowledge, this has not changed since before even C++98.
  • Admin
    Admin almost 7 years
    @BJovke - Of course naked raw owner pointers are bad style since C++11, and this example (without changes) has a memory leak as a result of that issue. Modern style = use a unique_ptr. A unique_ptr isn't implicitly castable IIRC, and it would probably violate uniqueness to support that cast, but I'd have to do some checking to be sure.
  • Admin
    Admin almost 7 years
    @BJovke - BTW - it's fairly common to claim that derived classes aren't distinct types from their bases, they're extensions of the same type. It's not an opinion I share, but it does reflect the OOP intent. That's why the implicit cast is supported for raw pointers and references.
  • Ignorant
    Ignorant almost 7 years
    In C++11 you can add the override keyword: void eat() override { std::cout << "I'm eating a rat."; } so that you know you are overriding an existing method of a base class (and make the compiler aware of it).
  • gawkface
    gawkface almost 7 years
    the concept of iterating on different types of (sub-)objects using a single (super-)object type should be highlighted, that's a good point you gave, thanks
  • Ahmad
    Ahmad almost 7 years
    @HeshamEraqi without virtual it is early binding and it will show "?" of base class
  • Drew Delano
    Drew Delano over 6 years
    @BJovke: Why in the world would you expect that to be a compile error, or even bad practice?
  • BJovke
    BJovke over 6 years
    @FredLarson You're right. It might not be a compile error. Regardless of that, in modern C++ it is considered as a bad practice to use explicit casts. For many cases it's also not advisable to use implicit casts (like in this case). This was true even for C long time ago, casts defeat the purpose of strongly typed language. Many developers of libraries in their classes forbid implicit conversions and/or not implement them at all. Furthermore, now that C++ has templates, this is the way use these objects.
  • Drew Delano
    Drew Delano over 6 years
    @BJovke: This is not a cast, implicit or explicit. It is a substitution. See the Liskov Substitution Principle.
  • Kaz
    Kaz over 6 years
    Without virtual you are not overloading. You are shadowing. If a base class B has one or more functions foo, and the derived class D defines a foo name, that foo hides all of those foo-s in B. They are reached as B::foo using scope resolution. To promote B::foo functions into D for overloading, you have to use using B::foo.
  • einpoklum
    einpoklum about 6 years
    Note that C++ compilers today can often optimize late into early binding - when they can be certain of what the binding is going to be. This is also referred to as "de-virtualization".
  • Admin
    Admin about 6 years
    @einpoklum - optimizing away the overhead is certainly a good point, but I'm not really sure it counts as optimizing late binding into early binding. The cases where the compiler can be certain in advance are cases where early binding and late binding are equivalent (give the same behavior) so the compiler has more freedom to choose implementations, but my impression of the terminology is that it's about meaning, not about implementation.
  • Admin
    Admin about 6 years
    One interesting case happens when there's a very common case (determined by instrumented code, I think most often for VM languages like Java) but other cases can still happen. The compiler may generate both specialised and general-case code, and have an "if it's the expected common-case type" check to choose between them. This is still devirtualisation, and it still makes a late-binding decision of which implementation to use.
  • einpoklum
    einpoklum about 6 years
    @Steve314: I mean, for example, cases in which you call a virtual function for a base-class pointer, but the compiler can tell that the pointed-to object will actually always have the same implementation of that method.
  • curiousguy
    curiousguy about 6 years
    @BradRichardson Non virtual calls are 100% predictable. Virtual introduces "unpredictable" behavior.
  • Lightness Races in Orbit
    Lightness Races in Orbit over 5 years
    @Brad There are schools of thought that say "you wouldn't" and therefore "make everything virtual". However, there is a cost to runtime polymorphism, both in terms of performance and in terms of being able to accurately and mathematically guarantee a program's behaviour and correctness. So, if you don't need it to achieve a goal, common wisdom is to avoid it. Like anything: pros and cons, use the right tool for the job.
  • Dan M.
    Dan M. over 5 years
    @curiousguy "Non virtual calls are 100% predictable", C++: "You are like a little baby, watch this: ADL, Two-phase name lookup, SFINAE, overloading".
  • Gabriel
    Gabriel over 5 years
    Virtual ist not needed but you can model your dynamic binding using dyno library: github.com/ldionne/dyno which already states in its title, that polymorphism by inheritance and virtual calls is not the way to go... Sady, these concepts of louis are still experimental, hopefully they find a way into the standar
  • Marc.2377
    Marc.2377 over 5 years
    @rexbelia That's great, but why not adding it as an answer instead?
  • hounded
    hounded over 5 years
    As a c++ newbie this is a great explanation of void functions. But hold on tonto.. I was confused with your object construction, Animal *animal = new Animal; After a tonne of googling I found this is creating a object dynamically and to quote stackoverflow.com/a/15310943/3241785, In Modern C++, this is regarded as a dubious programming practice
  • Mooing Duck
    Mooing Duck about 5 years
    @hounded: Unrelated to the problem. The "best" way is std::unique_ptr<Animal> animal = std::make_unique<Cat>();, which has the exact same issues.
  • Mooing Duck
    Mooing Duck about 5 years
    @Steve314: std::unique_ptr actually is implicitly castable for this case, specifically to handle this upcast cast, which are totally normal. It doesn't violate uniqueness, since it's a move constructor, and not a copy constructor.
  • Peter - Reinstate Monica
    Peter - Reinstate Monica almost 5 years
    Take my upvote because you show the perhaps most important use of polymorphism: That a base class with virtual member functions specifies an interface or, in other words, an API. Code using such a class frame work (here: your main function) can treat all items in a collection (here: your array) uniformly and does not need to, does not want to, and indeed often cannot know which concrete implementation will be invoked at run time, for example because it does not yet exist. This is one of the foundations of carving out abstract relations between objects and handlers.
  • Zhi Zheng
    Zhi Zheng over 4 years
    In summary,virtual function are maily used to achieve Runtime polymorphism
  • mLstudent33
    mLstudent33 about 4 years
    when would an intermediate function be necessary?
  • Yunfei Chen
    Yunfei Chen almost 4 years
    @MooingDuck If it has the same issues then how is it the best way????
  • gnasher729
    gnasher729 over 3 years
    "overloading" basically means you write another function that by pure coincidence has the same name as an existing one.
  • Coder100
    Coder100 over 3 years
    What does polymorphism have to do with this? It should be mentioned in the answer.
  • Nabs
    Nabs over 3 years
    I like this the most too. When I see the animal and dog example I had the exact same thought like why would you do that? This is a way better example of a practical way of understanding virtual functions. This one thing I'd to mention. The first example (animal and dog classes) in the original blog post is not complete. If I hadn't read the other examples before I woundn't have been able to understand it.
  • Peter - Reinstate Monica
    Peter - Reinstate Monica almost 3 years
    The code would illustrate the point at hand more strikingly if you renamed obj to basePtr.
  • Peter - Reinstate Monica
    Peter - Reinstate Monica almost 3 years
    @MooingDuck I think there is no such thing as an "implicit cast" -- that would be a conversion, right? "Cast" is the name for the syntax of explicit conversions, of which some -- those that may fail -- must be explicit (base pointer -> derived pointer), some not (the inverse).
  • Admin
    Admin almost 3 years
    @Peter-ReinstateMonica - I eventually noticed your comment is to MooingDuck, but as I already wrote this and as I often switch words like this too and maybe did in another comment MooingDuck is referencing - In the C++ standard I assume you're correct. I don't know if that distinction is specific to the C++ standard (which like any complex technical document, needs to define its own meanings for words that may be used differently elsewhere) or if that's a genuine strict distinction throughout programming/computer science or somewhere in-between. On the other point - accepted, will edit.
  • coderDude
    coderDude almost 3 years
    @YunfeiChen Because you would be avoiding potential memory leaks
  • gonidelis
    gonidelis over 2 years
    Why even declare Base* basePtr = new Derived ();?