2015-12-20 8 views
5

スライスを理解した後、私はそれが動的変数へのポインタを使用して壊れることがあることを理解しています。しかしどうして?なぜその時点でスライスしていないのですか?私は自分自身だと思うが、私はよく分からない。 ppet = pdog;割り当ての後、pdogはppetの同じアドレスを指します。それじゃない?仮想関数とポインタの使い方を理解する

//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 
} 

出力:

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 
+1

[OT]:キーワード 'override'は、実際にオーバーライドされているかどうかを確認するので、不要な' virtual'を書き込むよりも優れています。 – Jarod42

+1

私は決してキーワードとしてオーバーライドを聞いたことがなかった。少し説明できますか? @ Jarod42 – askque

+0

http://stackoverflow.com/questions/13880205/override-in-c11 – user007

答えて

3

派生クラスは、基本的に派生クラスが追加されます任意の追加フィールドが続くその基底クラスのインスタンスで「スタート」。だから、:

Derivedインスタンスがメモリ内にこのようになります
class Base { 
    int a, b; 
}; 

class Derived { 
    int c, d; 
}; 

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

あなたは今、 "スライス" は、それがBaseインスタンスに、この問題が発生した場合:オブジェクトへ

[a] [b]|nothing 

ポインタを一方、型にかかわらず常に同じサイズなので、ポインタへのポインタは派生オブジェクトを指し示すことができ、情報を失うことはありません。 DerivedオブジェクトのBase部分の先頭は、Derivedオブジェクトとまったく同じアドレスです。

0

クラスを定義すると、メンバーはそのメモリレイアウトを定義します。クラスデータメンバは、順次メモリに格納されます。

クラスを継承し、継承を使用すると、派生クラスのデータメンバーは、基本クラスのデータメンバーの後に追加されます。

このように、スライスが発生すると、基本クラスのメンバーだけを効果的に「見る」ことができます。質問「なぜポインタOTO基底クラスが派生クラスのオブジェクトをスライスしていない」に今

、?継承の最も重要な側面の

一つは、派生クラスのメンバ関数を提供することはないが、それが提供する関係は派生クラスと基本クラスの間で発現しました。派生クラスは、"基本クラスの型"と見ることができます。

詳細については、アップキャストおよびダウンキャストを確認してください。

アップキャスティングは、派生クラスのリファレンスまたはポインタをベースクラスに変換しています。言い換えれば、アップキャスティングは派生型を基底型として扱うことを可能にします。

あなたの質問に回答するには、「What's Override?そのをオーバーライド呼ば 基底クラスから仮想関数と同じ名前およびタイプの関数を導出