Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

understanding virtual function and pointer usage

After understanding of slicing, as far as I see that it can be broken using pointers to dynamic variables. But how come? Why is there no slicing at that point ? I think myself but I'm not sure. After the ppet = pdog; assignment, pdog points to same address of ppet. Doesn't it ?

//Program to illustrate use of a virtual function 
//to defeat the slicing problem.

#include <string>
#include <iostream>
using namespace std;

class Pet
{
public:
    virtual void print();
    string name;    
};

class Dog : public Pet
{     
public: 
    virtual void print();//Keyword virtual not needed, but put
                         //here for clarity. (It is also good style!)

string breed;
};

int main()
{
    Dog vdog;
    Pet vpet;

    vdog.name = "Tiny"; 
    vdog.breed = "Great Dane";
    vpet = vdog; 

    //vpet.breed; is illegal since class Pet has no member named breed

    Dog *pdog;
    pdog = new Dog;
    pdog->name = "Tiny";
    pdog->breed = "Great Dane";

    Pet *ppet; 
    ppet = pdog; 
    ppet->print(); // These two print the same output:
    pdog->print(); // name: Tiny breed: Great Dane

    //The following, which accesses member variables directly
    //rather than via virtual functions, would produce an error:
    //cout << "name: " << ppet->name << "  breed: " 
    //     << ppet->breed << endl;
    //generates an error message: 'class Pet' has no member
    //named 'breed' .
    //See Pitfall section "Not Using Virtual Member Functions"
    //for more discussion on this.

    return 0;
}

void Dog::print()
{
    cout << "name: " << name << endl;
    cout << "breed: " << breed << endl; 
}

void Pet::print()

{
    cout << "name: " << endl;//Note no breed mentioned
}

Output:

The slicing problem:
name: Tiny
Note that it was print from Pet that was invoked.
The slicing problem defeated:
name: Tiny
breed: Great Dane
name: Tiny
breed: Great Dane
like image 459
askque Avatar asked Oct 19 '22 19:10

askque


1 Answers

Derived classes essentially "start" with an instance of their base classes, followed by any additional fields the derived class adds. So:

class Base {
    int a, b;
};

class Derived {
    int c, d;
};

A Derived instance looks like this in memory:

[a] [b]|[c] [d]

If you now "slice" it into a Base instance, this happens:

[a] [b]|nothing

Pointers to objects on the other hand are always the same size regardless of type, so a pointer-to-base can point to a derived object and not lose any information. The beginning of the Base part of a Derived object is exactly the same address as the Derived object itself.

like image 176
John Zwinck Avatar answered Nov 15 '22 11:11

John Zwinck