3

Thispointer はClassName非 const メンバー関数の型を持っています。

 class Base
 {
   public:
     void get()
     {
       //this->put(); Why can't I call back a derived class method eventhough 
                       **this** is pointing to derived class object.
     }
 };

 class derived: public Base
 {
   public:
   void put()
   {
    // do somthing.
   }
 };

 int main()
 {
  derived d;
  //d.get();
  d.put();
  return 0;
 }

両方の関数でポインターの値をthis出力すると、それは同じであり、派生クラス オブジェクトに対して呼び出されたことを示します。また、thisポインタ型もderived *ここにあります。

また、私が理解してpointerいるように、メソッドを呼び出すときに to オブジェクトがある場合は、そのtoの現在から始まるoffset全体でメソッドが存在する場所を指しているだけです。object layoutaddresspointerobject

しかし、クラス内メソッドのアドレスを持っているのに、derivedクラスメソッドにオフセットできないのはなぜですか。start(derived)objectbase

上記の理解のためにこれを行うことができない理由を理解することはできません。ここで非常に基本的なものが欠けています。

4

6 に答える 6

8

あなたがコンパイラーだったとしましょう。次のクラスが表示されます。

class foo
{
    void bar() { this->xyz(); }
};

職業はなんですか?xyzが何であるかわからないこと、および のメンバ関数ではないことは確かだと不平を言いますfoofoo他のクラスを探し回って、それらがこの関数から派生して宣言されているかどうかを確認する必要はありません。逆に機能するだけです。

逆に言えば、派生クラスで実装するメソッドのシグネチャを宣言する必要があります。

class foo
{
    void bar() { this->xyz(); }
    virtual void xyz() = 0;
};

突然、これは有効になりましたが、インスタンスを作成できなくなりましたfoo。純粋に仮想メソッドを持つすべてのクラスは抽象クラスです。

ただし、これテンプレートで機能することに注意してください。

template <typename T>
class foo
{
    void bar() { t.xyz(); }
    T t;
};

各テンプレートはコンパイル時にインスタンス化されるため、上記のテンプレートではなく、たとえばfoo<xyz_class>そのような機能を提供する可能性のあるテンプレートを見ます。

于 2013-08-08T13:07:37.143 に答える
6

私: コンパイラが Base::get 関数をコンパイルするとき、Derived::put 関数を認識できません。

あなた : Derived:: は同じファイルに入れられていませんか? コンパイラがそれを認識できないのはなぜですか?

私: 誰かが 4 年後に Base から派生した Derived1::putttttt を別のファイルで定義した場合はどうなりますか?

あなた: うーん、多分私は理解しています。

于 2013-08-08T13:09:57.750 に答える
5

メソッド put() を virtual として宣言する必要があります。

class Base
{
public:
     virtual void put() = 0;
     void get()
     {
       //this->put(); Why can't I call back a derived class method eventhough 
                       **this** is pointing to derived class object.
     }
};

class derived: public Base
{
public:
    void put()
    {
    // do somthing.
    }
};

int main()
{
    derived d;
    //d.get();
    d.put();
    return 0;
}
于 2013-08-08T13:05:55.253 に答える
2

クラスは、オブジェクトBaseの一部としてのみ使用することを知りません。Derived一般に、多くの異なる派生クラスが存在する可能性があり、そのうちの 1 つまたは一部のみがput(). それでは、どのようBaseにコンパイルできますか?

オブジェクトへのポインターがある場合、それをキャストBaseへのポインターを取得し、その方法でメソッドを呼び出すことができます。DerivedDerived

Base* b = new Derived;
dynamic_cast<Derived*>(b)-> put();

必要に応じて、クラスは実際にthis派生インスタンス ポンターにキャストできます。

dynamic_cast<Derived*>(this)-> put();
于 2013-08-08T13:05:29.627 に答える
1

derived投稿したコードはコンパイルされません。これは、コンパイラがclass Base. thisポインターは、クラスのすべての非静的メンバー関数に暗黙的に渡されるポインターであり、その関数がそのインスタンスのメンバー属性にアクセスする方法です。Baseクラス メンバ関数でthisは、型がBase * あります。constメンバ関数では、型がありconst Base *ます。

また、これthisは非左辺値であり、値を割り当てることができないことを意味します。

以下は、this ポインターに関する C++ 標準からのものです。

9.3.2 this ポインタ

非静的 (9.3) メンバー関数の本体では、キーワード this は、関数が呼び出されるオブジェクトのアドレスを値とする prvalue 式です。クラス X のメンバー関数での this の型は X* です。メンバー関数が const と宣言されている場合、this の型は const X* であり、メンバー関数が volatile と宣言されている場合、this の型は volatile X* であり、メンバー関数が const volatile と宣言されている場合、this の型は const です。揮発性 X*.

あなたの質問でやりたいことをするために、次のコンパイル

#include <iostream>
class Base
{
   public:
     void get();
};


class derived: public Base
{
   public:
   void put()
   {
        std::cout << "This is a bad idea" << std::endl;

   }
};


void Base::get()
{
    //compiler knows what dervied class is
    static_cast<derived *>(this)->put();  
}


 int main()
 {
    derived d;
    d.get();

    return 0;
 }

出力は次のとおりです。This is a bad idea

目的の動作を実現するには、仮想関数またはテンプレートを使用することをお勧めします。

于 2013-08-08T13:31:30.653 に答える
1

基本クラスにメソッドを記述this->put()したとします。コンパイル時に、コンパイラは同じクラスの put() 関数をチェックします。そのようなものがないため、コンパイル時エラーが表示されます。

于 2013-08-08T13:23:04.583 に答える