サブクラスでベースクラスの純虚関数のアクセス表現ドメインを変更する

4375 ワード

サブクラスでベースクラスの純虚関数のアクセス表現ドメインを変更する
虚関数についての学習ノート.間違いや改善すべき点を指摘してください.
内容:
ベースクラスの虚関数はprivateとして宣言され、サブクラスではpublicとして宣言されます.
ベースクラスの虚関数はpublicとして宣言され、サブクラスではprivateとして宣言されます.
虚関数では非虚関数が呼び出され、非虚関数では虚関数が呼び出されます.
多くの人が簡単に見えるかもしれませんが、虚関数テーブルを理解するのに役立つと思います.
テストコード:
#include <iostream>

using namespace std;

class Base {

public:

virtual void info() = 0;

private:

virtual void print() = 0;

};

class DeriveFirst : public Base {

public:

virtual void print() { cout << "DeriveFirst::Base" << endl; }

private:

virtual void info() { cout << "DeriveFirst::info" << endl; }

};

int main()

{

Base *b = new DeriveFirst;

DeriveFirst *df = new DeriveFirst;

//b->print();

df->print();

b->info();

//df->info();

return 0;

}


コメントされた2行は、コンパイル時にエラーが表示されます.
testVirtual.cpp: In function ‘int main()’:
testVirtual.cpp:9: error: ‘virtual void Base::print()’ is private
testVirtual.cpp:25: error: within this context
testVirtual.cpp:18: error: ‘virtual void DeriveFirst::info()’ is private
testVirtual.cpp:28: error: within this context
静的タイプは、アクセス可能な関数とアクセス不可能な関数を決定するので、b->print()、df->info()はアクセス不可をプロンプトします.
動的タイプは、特定の関数が呼び出されるかどうかを決定するので、b->info()はそのサブクラスのinfo関数を呼び出します.興味深いことに、サブクラスのinfo()はprivateです.この場合、虚関数テーブルが機能するためです.
虚関数が他の関数を呼び出すと、その関数が虚関数であるかどうかにかかわらず、呼び出されるのはサブクラスで実現される虚関数です.
//test1.cpp
#include <iostream>

using namespace std;

class A {

public:

void fun_a() { cout << "int A::fun_a" << endl; }

virtual void fun_b() {

fun_a();

cout << "int A::fun_b" << endl;

}

};

class B : public A {

private:

void fun_a() { cout << "int B::fun_a" << endl; }

void fun_b() {

fun_a();

cout << "int B::fun_b" << endl;

}

};

int main()

{

A *test = new B();

test->fun_a();

test->fun_b();

return 0;

}
//test2.cpp
#include <iostream>

using namespace std;

class A {

public:

virtual void fun_a() { cout << "int A::fun_a" << endl; }

void fun_b() {

fun_a();

cout << "int A::fun_b" << endl;

}

};

class B : public A {

private:

void fun_a() { cout << "int B::fun_a" << endl; }

void fun_b() {

fun_a();

cout << "int B::fun_b" << endl;

}

};

int main()

{

A *test = new B();

test->fun_a();

test->fun_b();

return 0;

}


個別出力:
int A::fun_a
int B::fun_a
int B::fun_b
test呼び出しfun_b時に虚関数で探し、サブクラスのfun_を呼び出すb,サブクラスのfun_b実装、使用する自然は再定義後のfun_a.アセンブリに詳しい人は、アセンブリがここにあるジャンプ命令を見ることができます.アセンブリコードにfun_bの実装でここで呼び出されたのはB::fun_a.
int B::fun_a
int B::fun_a
int A::fun_b
test呼び出しfun_b時に虚関数表で探すことはなく、直接A::fun_を呼び出すb、ただしfun_に呼び出されるaサブクラスfun_を呼び出す必要があるかどうかをチェックします.a.