C++11クラスのマルチステート

10291 ワード

c++のクラスの3つの特性は、継承、パッケージ、マルチステートです.最近コードを書くのにクラスの多態性が使われているので、ここでまとめてみます.
一、多態の定義
多態の定義については、大物の文章に自分の理解を加えて以下の内容を得たものを参考にしています.
1.1マルチステートの定義
多態性は簡単に「1つのインタフェース、複数の方法」にまとめることができます.c++にはインタフェース(interface)というキーワードは存在しないが、マルチステートで実現でき、マルチステートの目的はインタフェースの再利用である.C++マルチステートは虚関数(virtual)で実現され、虚関数はサブクラスがメンバー関数を再定義することを可能にし、サブクラスが親を再定義する方法はオーバーライド(override)と呼ばれ、あるいは書き換えと呼ばれている.overrideでは、関数名とパラメータリストが親と一致する必要があります.overrideキーワードは、派生クラスで宣言されたリロード関数がベースクラスの虚関数と同じ署名であることを確認するために、c++11の後に追加されます.example.
1.2 overrideとoverloadの違い
もう1つの中国語の意味でこれと混同されやすいc++メソッドはリロード(overload)と呼ばれ、overloadは複数の同名の関数を許可するが、これらの関数のパラメータリストは異なり、許可パラメータの個数は異なり、パラメータのタイプは異なり、あるいは両者は異なる.override+virtualのみがマルチステートであり、overloadはマルチステートではない.コンパイラの観点からoverride+virtualで実現される関数は、プリコンパイル時に1つのプリプロセッシング関数しか生成されませんが、overloadは様々な状況に応じて異なるプリプロセッシング関数を生成します.
1.3多態と非多態の実質的な違い
マルチステートと非マルチステートの実質的な違いは,関数アドレスが早期バインドか遅いバインドかである.関数の呼び出しの場合、コンパイラのコンパイル中に関数の呼び出しアドレスを決定し、コードを生成することができます.静的です.つまり、アドレスは早期にバインドされています.一方、関数呼び出しのアドレスがコンパイラ中に決定できない場合は、実行時に決定する必要があります.これは遅いバインドです.マルチステートの最も一般的な使い方は、ベースクラスを宣言するポインタであり、このポインタを使用して任意のサブクラスオブジェクトを指し、対応する虚関数を呼び出し、指すサブクラスによって異なる方法を実現することができます.虚関数が使用されていない場合、すなわちC++マルチステートが利用されていない場合、対応する関数をベースクラスポインタで呼び出すと、常にベースクラス関数自体に制限され、サブクラスで書き換えられた関数を呼び出すことができない.多態性がないため、関数呼び出しのアドレスは一定であり、固定されたアドレスは常に同じ関数に呼び出され、1つのインタフェース、複数の方法の目的を実現することはできません.
二、多態の例
talk is cheap , show me the code.
/*
*** in  Parent.h  file
*/
using namespace std;
class Parent
    {
    public:
        virtual ~Parent();

        /// 
        /// function.
        /// 
        virtual void initialize() = 0;

        inline const vector<pair<int, wstring> getNames() { return mNames; }
        inline const vector<wstring> getResources() { return mResources; }
    protected:
        vector<pair<int, wstring>> mNames;
        vector<wstring> mResources;
    };

以上code是一个基类的声明,在基类的实现文件中就写一个析构函数即可。这里只有析构函数被声明为了虚函数,那构造函数能不能声明为虚函数呢?答案是不能
**原因:**虚函数的实现是通过对象内存中的vptr来实现的。而构造函数是用来实例化一个对象的,通俗来讲就是为对象内存中的值做初始化操作。那么在构造函数完成之前,也即还没有进行初始化,此时vptr是没有值的,也就无法通过vptr找到作为构造函数和虚函数所在的代码区,所以构造函数只能以普通函数的形式存放在类所指定的代码区中。而对于析构函数,当我们delete(a)的时候,如果析构函数不是虚函数,那么调用的将会是基类base的析构函数。而当继承的时候,通常派生类会在基类的基础上定义自己的成员,此时我们当然希望可以调用派生类的析构函数对新定义的成员也进行析构。
上面的code中还涉及到了一个概念,就是纯虚函数virtual void initialize() = 0;,纯虚函数也是虚函数,它的区别在于声明的时候赋值为0,纯虚函数告诉编译器要求子类必须overide这个函数才能编译通过,正常虚函数的话即使子类没有override这个虚函数也是可以编译通过的。
接下来来看子类的实现:

/*
*** in Child.h file
*/
class Child: public Parent
    {
    public:
        /// 
        /// function 
        /// 
        virtual void initialize() override;
    };

在子类的声明中,虽然虚函数的参数列表和返回类型都与父类一致,但是后面加上override是为了保证出现一些不必要的失误,达不到override的需求。

/*
*** in Child.cpp file
*/
void Child::initialize()
{
    vector<pair<int, FontName>>().swap(mNames);
    vector<wstring>().swap(mResources);
    for(int i = 0 ; i < 2;++i)
    {
        mResources.emplace_back(i >= 1 ? L"Mother" : L"Dad");
        mNames.emplace_back(i >= 1 ? L"Xiaofang" : L"Xiaoming");
    }
}

サブクラスの定義ではparentというクラスの虚関数が実現される.呼び出しプロセスは次のとおりです.
/*
***in main.cpp
*/
auto mPeople = std::make_unique<Child>();
mPeople->initialize();//    child   
auto& names = mPeople->getNames();
auto& resources = mPeople->getResources();


これによりクラスのマルチステートが実現される.overrideはc++11が新しく加入したキーワードなので、このブログではc++11と言います.以上です.