Virtual functions - base class pointer

I figured out why a base class pointer is made to point to a derived class object. But I don't understand why we need to assign a base class object to it when it is a base class object by itself.

Can someone explain this?

#include <iostream>
using namespace std;
class base {
     public:
        virtual void vfunc() {
            cout << "This is base vfunc().\n";
         }
};
 class derived1 : public base {
      public:
            void vfunc() {
                 cout << "This is derived1 vfunc().\n";
    }
};
int main()
{
     base *p, b;
     derived1 d1;
     // point to base
     p = &b;
     p->vfunc(); // access base vfunc()
     // point to derived1
     p = &d1;
     p->vfunc(); // access derived1 vfunc()
     return 0;
}

      

+3


source to share


4 answers


Because pointers by themselves can't do anything.
The pointer must point to a valid object for you to use it.

Why the above statement?

A step-by-step explanation will probably clear up your doubts.

Step 1:

base *p;

      

Creates a pointer p

that can store the address of an object of the class base

. But it is not initialized, it points to any random address in memory.

Step 2:



p = &b;

      

Assigns the address of a valid object to the base

pointer p

. p

now contains the address of this object.

Step 3:

p->vfunc(); // access base vfunc() 

      

Sets a pointer p

and calls a method on the vfunc()

object that it points to. ie The: b

.

If you remove Step 2: your code will just try to dereference the uninitialized pointer and cause the Undefined Behavior and most likely fail.

+3


source


It is not necessary to call

p = &b;
p->vFunc();

      

you can call directly

b.vFunc();

      



both will give you the same result.

However, it looks like you need to understand the power of virtual functions. Suppose you want to keep 10 instances of objects base

or derived1

and call the function again, how would you do it? or after storing it in an array if you want to pass it to a generic function?

vase *p[4];

base b1;
derived d;

p[0] = new base();

p[1] = &b1;

p[2] = new dervied1();    

p[3] = &d;

for (int i =0 ;i <4 ;i++)
{
  p[i]->vFunc();
}

      

+1


source


I'm not entirely sure if I understand your question correctly, but a typical use case for a virtual function is when we write a function and want it to work on an object of the base class or something derived from it:

struct base { 
    virtual void dosomething() = 0;
};

void myfunc(base *b) {
    b->dosomething();
}

      

When we write myfunc

, we do not know or care about the exact identity of the object - we just care about what it knows as dosomething

on command.

As far as coding is concerned, as you showed, where we directly assign the addresses of base or derived class objects to a pointer, this is more the exception than the rule. You are absolutely correct that in a situation like this we don't get much from using a pointer to a base to refer to a derived object. The main advantage is a kind of function, in which the derived class does not yet exist when we write the code, but as long as the derived class conforms to the specified interface, it will work.

+1


source


This type of reference applies very well when you want to apply design patterns (you may need to take an advanced course in object-oriented design or start by reading a book: head first, design patterns, I suggest)

see for example how to implement decorator pattern in java in the referenced book.

public abstract class Beverage {
String description = "Unknown Beverage";
public String getDescription() {
    return description;
}
public abstract double cost();   
}

      

then think we have espresso and DarkRoast as two child classes:

public class Espresso extends Beverage {

public Espresso() {
    this.description = "Espresso";
}

public double cost() {
    return 1.99;
}
}

public class DarkRoast extends Beverage {
public DarkRoast() {
    description = "Dark Roast Coffee";
}

public double cost() {
    return .99;
}
}

      

we're going to add a decorator:

public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
 }

      

and build some concrete decorator:

public class Mocha extends CondimentDecorator {

Beverage beverage;

public Mocha(Beverage beverage) {
    this.beverage = beverage;
}

public String getDescription() {
    return beverage.getDescription() + ", Mocha";
}

public double cost() {

    return .20 + beverage.cost();
}
} 

      

and another wrapper:

public class Whip extends CondimentDecorator {
Beverage beverage;

public Whip(Beverage beverage) {
    this.beverage = beverage;
}

public String getDescription() {
    return beverage.getDescription() + ", Whip";
}

public double cost() {
    return .10 + beverage.cost();
}
}

      

finally, take a look at what happened in the main function and how we take advantage of the father's class pointer:

public static void main(String[] args) {
    Beverage beverage = new Espresso();
    System.out.println(beverage.getDescription() + " $" + beverage.cost());
    Beverage beverage2 = new DarkRoast();
    beverage2 = new Mocha(beverage2);
    beverage2 = new Mocha(beverage2);
    beverage2 = new Whip(beverage2);
    System.out.println(beverage2.getDescription() + " $" + beverage2.cost());

      

Can you guess what the exit is? and:

Espresso $1.99
Dark Roast Coffee, Mocha, Mocha, Whip $1.49

      

-2


source







All Articles