Help us understand the problem. What is going on with this article?

NVIとautoキーワードの相性の悪さ

More than 5 years have passed since last update.

さて、C++の深い話的なやつを書いてくつもりではあるのですが、さしあたり、「なんぞこれ...」 っていうの見つけたので書いておこうと思う。
解決策的なのとかがあれば誰かご教授ください。

autoキーワード

autoキーワードはC++11から導入されたインスタンス化される実態を元に型を決めるっていうやつです。型をそんなに意識しなくて良くなるのですが、僕はなんか好きになれないでいたんですわ。便利といえば便利だけど。

auto.cpp
#include <iostream>
using namespace std;
int main() {
    auto a = 10;
    cout << a <<endl; // -> 10
}

NVIパターン

NVIっていうイディオムがあります。書き方はつまりは Template methodの書き方と同じです。 公開インターフェース(public)な関数はvirtualつけるんじゃないよ。っていう意味です。何がいいかと一言で言うと、ダッグタイピングした際に継承先で挙動を変更させないで、基底クラスの公開インターフェースが使われるので、インターフェース部分の破壊が防がれるってことです。

NVI.cpp
#include <iostream>
using namespace std;

class Base {
private:
    //中身は未実装。これはカスタマイズポイント
    void a() = 0;
    void b() = 0;
public:
    //単にa()とb()を実行する関数。これはオーバーライドさせるつもりではない
    void c() {
        a();
        b();
    }
};

class Derived : public Base {
private:
    void a() {
        cout << "a" << endl;
    }
    void b() {
        cout << "b" << endl;
    }
    void c() {
       cout << "test derived" << endl;
    }
};

int main() {
    Base* base = new Derived();
    base->c(); // -> a \n b

    auto base = new Derived();
    base->c(); // -> test derived
}

なんということか... いや、そりゃそうだろって思うけど。
つまりは何が言いたいかっていうと実態にしか目を当てないautoってやり方と、クラスの継承関係を強く意識してコードを書くNVIのやり方がすごいちぐはぐになって見えるのは僕だけでしょうか。

つまりは、C++11移行だぜ!って言ってダッグタイピングしているところを全部autoで書き直していくと、継承先で名前がぶつかっていた場合 予期せぬ壊れ方をしそうな気がします。Base型で Derivedをインスタンス化した場合とかをよく意識して書いていたのにこれからautoばっかつかう感じになると不幸な時代が来るかもしれません。唯一の解決策としては、オーバーライドするつもりなら、 overrideキーワードを付けろってことになりますね...

override.cpp
#include <iostream>
using namespace std;

class Base {
private:
    //中身は未実装。これはカスタマイズポイント
    void a() = 0;
    void b() = 0;
public:
    //単にa()とb()を実行する関数。これはオーバーライドさせるつもりではない
    void c() {
        a();
        b();
    }
};

class Derived : public Base {
private:
    void a() {
        cout << "a" << endl;
    }
    void b() {
        cout << "b" << endl;
    }
    // Base::c()はvirtualじゃないのでコンパイルエラー!!!
    void c() override {
       cout << "test derived" << endl;
    }
};

int main() {
    Base* base = new Derived();
    base->c(); // -> a \n b

    auto base = new Derived();
    base->c(); // -> test derived
}

これでコンパイル時にバグをつぶせそうですが... overrideを強制する仕掛けはないんですかね。

yoshiya0503
ブログ的な技術備忘録をこっちに移設しようと思います。 twitter -> yoshiya0_0 gitHub -> yoshiya0503 旧ブログ -> http://ameblo.jp/myon53/entry-11797609797.html Node.js MongoDB Python C++ Cassandra ... いろんなことで飯の種を作っています。宜しくお願いします。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away