ローカル関数

Problem
ある関数の呼び出しを特定の関数のみに限定した場合、どのようにすれば良いでしょうか?

Solution
以下のような関数is_oddがあったとします。
#include <vector>
#include <algorithm>
#include <iostream>

bool is_odd(int x)
{
  return x % 2;
}

int main()
{
  std::vector<int> v;
  v.push_back(0);
  v.push_back(1);
  v.push_back(2);
  
  std::cout << *std::find_if(v.begin(), v.end(), is_odd) << std::endl;
  
  return 0;
}
main以外からはis_oddの呼び出しを禁止したい場合、staticメンバ関数を用いたHackで関数内に関数を定義することができます。ローカル変数ならぬローカル関数です。
#include <vector>
#include <algorithm>
#include <iostream>

int main()
{
  struct local {
    static bool is_odd(int x)
    {
      return x % 2;
    }
  };
  
  std::vector<int> v;
  v.push_back(0);
  v.push_back(1);
  v.push_back(2);
  
  std::cout << *std::find_if(v.begin(), v.end(), local::is_odd) << std::endl;
  
  return 0;
}

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

オブジェクト指向における再利用のためのデザインパターン

オブジェクト指向における再利用のためのデザインパターン オブジェクト指向における再利用のためのデザインパターン
エリック ガンマ、ラルフ ジョンソン 他 (1999/10)
ソフトバンククリエイティブ
この商品の詳細を見る

デザインパターンのバイブル、オブジェクト指向における再利用のためのデザインパターンです。

本書がプログラミングにおけるデザインパターンの始まりであり、本書出版以降、デザインパターンは全てのプログラマが必須の知識となりました。

現在では、デザインパターンに関する良書が多く出版されていますが、共通語彙としてのデザインパターンを語る上で、外すことができない重要な原典となっています。また、著者の4人組みは敬意を込めてGoF(Gang of Four)と呼ばれており、本書はGoF本と呼ばれることもあります。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

NVIイディオム

Problem
NVIイディオムとは、どのようなイディオムでしょうか?

Solution
例えば、以下のようなコードがあったとします。
#include <iostream>
#include <tr1/memory>

class Base {
public:
  virtual ~Base() {}
  virtual void something(const char* text)
  {
    std::cout << "Base::something(" << text << ")" << std::endl;
  }
};

class Derived : public Base {
public:
  virtual ~Derived() {}
  virtual void something(const char* text)
  {
    std::cout << "Derived::something(" << text << ")" << std::endl;
  }
};

int main()
{
  std::tr1::shared_ptr<Base> p(new Derived);
  p->something("message");
  return 0;
}
ここで assert(text); のような事前条件を追加したくなった場合、2つの仮想関数に対して修正を行わなければなりません。
class Base {
public:
  virtual ~Base() {}
  virtual void something(const char* text)
  {
    assert(text);
    std::cout << "Base::something(" << text << ")" << std::endl;
  }
};

class Derived : public Base {
public:
  virtual ~Derived() {}
  virtual void something(const char* text)
  {
    assert(text);
    std::cout << "Derived::something(" << text << ")" << std::endl;
  }
};
これではコードの重複を避けるというプログラミングの基本原則に反することになります。
この問題を回避するためには、Template Methodパターンを用います。

Template Methodパターンとは、オブジェクト指向における再利用のためのデザインパターンによると
1 つのオペレーションにアルゴリズムのスケルトンを定義しておき、その中のいくつかのステップについては、
サブクラスでの定義に任せることにする。Template Method パターンでは、アルゴリズムの構造を変えずに、
アルゴリズム中のあるステップをサブクラスで再定義する。 
とあります。
実際に、Template Methodパターンを適用すると次のようなコードになります。
class Base {
public:
  virtual ~Base() {}
  virtual void something(const char* text)
  {
    assert(text);
    something(text);
  }
  virtual void doSomething(const char* text)
  {
    std::cout << "Base::something(" << text << ")" << std::endl;
  }
};

class Derived : public Base {
public:
  virtual ~Derived() {}
  virtual void doSomething(const char* text)
  {
    std::cout << "Derived::something(" << text << ")" << std::endl;
  }
};
Template Methodパターンを適用することで、コードの二重化を避けることができましたが、更に考えを進めてみましょう。
まず、インターフェースとしてのsomething()ですが、something()自身が仮想関数の呼び出しを行っているので、something()自身は仮想関数である必要はありません。むしろ、非仮想仮想である方が望ましいです。また、doSomething()に関しては、メンバ関数であるsomething()から呼び出せれば良いだけなのでpublicである必要はありません。privateもしくはprotectedに変更しましょう。
class Base {
public:
  virtual ~Base() {}
  void something(const char* text)
  {
    assert(text);
    something(text);
  }
private:
  virtual void doSomething(const char* text)
  {
    std::cout << "Base::something(" << text << ")" << std::endl;
  }
};

class Derived : public Base {
public:
  virtual ~Derived() {}
private:
  virtual void doSomething(const char* text)
  {
    std::cout << "Derived::something(" << text << ")" << std::endl;
  }
};
これがNVI(Non Virtual Interface)と呼ばれるイディムです。

人気blogランキングへ にほんブログ村 IT技術ブログへ FC2ブログランキングへ

« 前頁へ移動する  | HOME |  次頁へ移動する »

ブログ内検索


このサイト内ウェブ全体
この検索は「緑のgoo」を利用しています

カテゴリー

未分類 (0)
C++ (24)
Books (11)
Bookmarks (1)

最近のエントリ

移植性の高いコードを書くためには (02/16)
ハッシュコンテナ - Part3 (01/10)
ハッシュコンテナ - Part2 (10/29)
日本語によるC++0xに関する記事 (10/23)
foreach (08/03)

Books

C++
プログラミング
デザインパターン
オブジェクト指向

RSSフィード

最新記事のRSS
最新コメントのRSS
最新トラックバックのRSS

アーカイブ

2008年02月 (1)
2008年01月 (1)
2007年10月 (2)
2007年08月 (1)
2007年07月 (2)
2007年06月 (1)
2007年05月 (2)
2007年04月 (1)
2007年03月 (2)
2007年02月 (2)
2007年01月 (3)
2006年12月 (4)
2006年11月 (8)
2006年10月 (6)

連絡先

email.png

Amazon