5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

クラスへの機能のちょい足し

Last updated at Posted at 2015-02-28

クラスにある機能をちょい足ししたいときに継承をつかうと便利です。

例えば、std::stringの+=演算子はcharを受け取ることができますが、暗黙の変換によって好ましくない引数を受け付けます。

std::string str = "abc";
str += 'd'; // OK
str += 10;  // OOPS! no warning or error

ユーザは"abcd10"という入力をしたつもりでも、10は実際にはchar型に変換され、'd'のときと同じ関数によって処理されます。よって、意図しない動作を引き起こしていると言えます。(C言語では文字リテラルはint型ですが、C++ではchar型です。)
しかし、これの解決のためだけに自分でstringクラスを定義したくないので、ちょい足しをしましょう。

namespace my
{
template < class tchar,
           class traits = std::char_traits < tchar >,
           class alloc = std::allocator < tchar > >
class basic_string : public std::basic_string < tchar, traits, alloc >
{
public:
  using base = std::basic_string < tchar, traits, alloc >;

  using base::base;
  using base::operator +=;
  template < class Ty > basic_string& operator += ( Ty ) = delete; // ちょい足し
};
using string = basic_string < char >;
using wstring = basic_string < wchar_t >;
} // namespace my

コンストラクタも他の機能も全てベースクラスの流用です。流用に明示が必要な関数だけ書いてあげましょう。この場合、コンストラクタと+=演算子が明示してあります。これがないと関数が隠蔽されてしまい、元の機能が利用できません。

オーバーロード解決は暗黙の型変換よりもテンプレートを優先しますので、簡単なちょい足しで意図しない操作を防ぐことが出来ました。

std::string str1;
str1 += 10; // OOPS, operator +=( char ) is called.
my::string str2;
str2 += 10; // error, operator +=( int ) is deleted function.

もっとも、整数つなげたいのならstd::ostringstreamを使うべきで、+= 演算子で整数をつなげてはいけないのですが、エラーにすらならないのはさすがに不親切ですよね。

継承によるちょい足しはベースにしたクラスと互換性があるので、独自のものを使って困るということはたぶんありません。というか、互換性がなくなるほどの改造はちょい足しの範疇に入りません。特に、デストラクタにはよく注意する必要があります。

5
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?