C++居然能用父类指针(里面存的也是父类)调用子类(子类独有的)函数?
伊谢尔伦
伊谢尔伦 2017-04-17 14:21:02
0
4
538

昨天问另外一个问题的时候, 今天早上有人回复给出了这样一段代码, 我试着运行了一下, 结果却大大出乎我的意料 :

class Father
{
public:
    virtual void func1() { std::cout << "Father" << std::endl; }
    virtual ~Father(){}
};
class Son :public Father
{
public:
    virtual void func1(){ std::cout << "Son1" << std::endl; }
    void func2(){ std::cout << "Son2" << std::endl; }
    virtual ~Son(){}
};
class Factory
{
private:
    Father* myFather;
public:
    void setFun(Father* m_Father) { myFather = m_Father; }
    Father* getFun() { return myFather;};
};

int main()
{
    Father *m_Father = new Father();
    Factory* m_Factory = new Factory();
    m_Factory->setFun(m_Father );
    m_Factory->getFun()->func1();
    dynamic_cast<Son*>(m_Factory->getFun())->func2();
    ///
    return 0;
}

运行结果是 :

Father
Son2

这让我感觉特别的奇怪 :
首先对于main中的变量m_Father, 他的静态类型和动态类型都是Father指针, 之后使用dynamic_cast<Son*>进行强制转换, 按照我的设想, 只有当m_Father的动态类型, 也就是实际指向一个Son的时候, 转换才能够成功, 然而这里不但成功转换, 同时还调用了Son独有的函数fun2, 这不是太奇怪了吗?

伊谢尔伦
伊谢尔伦

小伙看你根骨奇佳,潜力无限,来学PHP伐。

全員に返信(4)
PHPzhong

サブクラスにデータ メンバーを追加し、func が呼び出されたときにそれを出力してみます。

いいねを押す +0
Peter_Zhu

C では、クラスのメンバー関数は C の関数と本質的には異なるものではないことを理解する必要があります。それらはメモリ内のコードの一部にすぎません。ここで fun2 についても同様です。ポインタを Son* 型に変更して (Son*)->func2() を呼び出すと、C はそれを Son$func2... のような関数シグネチャに変換するだけで、シンボル テーブルに移動して関数シグネチャを確認します。対応するメモリ位置を指定して、関数

を実行します。

プログラムでは、dynamic_cast<Son*>(m_Factory->getFun()) は正常に変換されず、null ポインターですが、アドレス指定は成功しているため、メンバー関数は null ポインターで呼び出すことができます

いいねを押す +0
黄舟

クラスのオブジェクトインスタンスでは、メンバー変数のみがメモリレイアウトに格納され、仮想がある場合はvptrが追加され、クラスのメンバー関数は個別に格納されます。
コード内のクラスにメンバー変数がなく、仮想関数が含まれていない場合は、NULL を指すクラス ポインターを指定して呼び出しても、成功します。これは、C 言語での関数の呼び出しに似ています。

いいねを押す +0
大家讲道理

一見すると、C の糖衣構文に中毒された患者のように見えます (笑)。これら 2 つのクラスは、基本的に親クラスを継承します。本質的には、父親へのポインタが含まれているだけです。強制は、変換オブジェクトに基づく結合です。したがって、son の属性のみが変換された属性として取得されます。そして、二人とも父親の血を継いでいるので、変換は問題ありません

いいねを押す +0
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート