简体   繁体   English

理解虚函数和指针用法

[英]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; ppet = pdog; assignment, pdog points to same address of ppet. 赋值,pdog指向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: Derived实例在内存中看起来像这样:

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

If you now "slice" it into a Base instance, this happens: 如果您现在将其“切片”为Base实例,则会发生以下情况:

[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. Derived对象的Base部分的开头与Derived对象本身的地址完全相同。

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" ? 现在,在问题“为什么指针oto基类不切片派生类的对象”

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. Upcasting将派生类引用或指针转换为基类。 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 . 从基类派生与虚函数具有相同名称和类型的函数,称为覆盖

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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