简体   繁体   中英

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

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.

When you define a class , its members define its memory layout. The class data members are stored sequentially in memory.

When you derive classes and inheritance is used, the data members of the derived class are simply added after those of the base class.

Thus, when slice happens you are effectively "seeing" only the base class members.

Now, on the question "Why are pointers oto base class not slicing objects of derived class" ?

One of the most important aspect of inheritance is not that it provides member functions for the derived class, but that it provides a relationship expressed between the derived class and the base class. The derived class could be seen as "a type of the base class" .

For further reading check the terms upcasting and downcasting .

Upcasting is converting a derived-class reference or pointer to a base-class. In other words, upcasting allows us to treat a derived type as though it were its base type.

To answer the your questions from the comments section, "What's Override?

Deriving a function of the same name and type as a virtual function from a base class its called overriding .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM