noexcept (C++11、 C++17)
C++11 で 追加 さ れ た noexcept キーワード を 使う と、 関数 が 例外 を 送出 する 可能性 が、 ある のか ない のかを 示す こと が でき ます。 この よう な 機能 を、 例外 仕様 と 呼び ます。
void f1() noexcept; // 例外 を 送出 し ない
void f2(); // 例外 を 送出 する かも しれ ない
void f1() noexcept {}
void f 2() {}
int main() {
f1();
f2();
}また、 noexcept には bool 型 の オペランド を 指定 する こと も でき ます。 noexcept 自身 が “no” で 始まる 否定 形 なので、 ややこしい の です が、 true ならば 例外 を 送出 し ない、 false ならば 例外 を 送出 する 可能性 が ある こと を 表し ます。
void f3() noexcept(true); // 例外 を 送出 し ない
void f4() noexcept(false); // 例外 を 送出 する かも しれ ない
void f3() noexcept(true) {}
void f4() noexcept(false) {}
int main() {
f3();
f4();
}移譲コンストラクタ (C++11)
C++11 には、 移譲 コンス トラクタ という 機能 が 追加 さ れ て おり、 コンス トラクタ から、 同じ クラス の 他 の コンス トラクタ を 呼び出せる よう になり まし た。
#include < iostream >
class MyClass {
public:
MyClass( int a) : MyClass( a, 0) {
std::cout << "MyClass( int)" << std::endl;
}
MyClass( int a, int b) : mA( a), mB( b) {
std::cout << "MyClass( int, int)" << std::endl;
}
private:
int mA, mB;
};
int main() {
MyClass mc1( 10);
MyClass mc2( 1, 2);
}実行結果: MyClass( int, int) MyClass( int) MyClass( int, int)
継承コンストラクタ (C++11)
C++11 には、 基底 クラス の コンス トラクタ を 派生 クラス で そのまま 使える よう に する、 継承 コンス トラクタ の 機能 が 追加 さ れ て い ます。派生 クラス の 側 に「 using 基底 クラス 名:: コンス トラクタ 名;」 の よう な 形 で 記述 する と、 基底 クラス の すべて の コンス トラクタ が、 派生 クラス 側 でも 使える よう になり ます。
#include < iostream >
class Base {
public:
Base( int a) {
std::cout << "Base( int)" << std::endl;
}
Base( const char* s) {
std::cout << "Base( const char*)" << std::endl;
}
};
class Derived : public Base {
public:
using Base::Base; // 引数 が const char* の コンス トラクタ は、 派生 クラス で 定義
Derived( const char* s) : Base( s) {
std::cout << "Derived( const char*)" << std::endl;
}
};
Derived d(" xyz"); // OK int
main() {}実行結果: Base( const char) Derived( const char)
override (C++11)
C ++ 11 では、 メンバ 関数 の オーバーライド を 行っ て いる こと を 明示 的 に 示す、 override という キーワード が 追加 さ れ て い ます。
#include < iostream >
class Base {
public: virtual void SetData( int id) {
std::cout << "Base (int)" << std::endl;
}
virtual void SetData( const char* name) {
std::cout << "Base (const char*)" << std::endl;
}
};
class Derived : public Base {
public: struct Param {};
void SetData( int id) override {
std:: cout << "Derived (int)" << std:: endl;
}
void SetData( const char* name) override {
std::cout << "Derived (const char*)" << std::endl;
}
virtual void SetData( const Param& param) {
std::cout << "Derived (const Param&)" << std::endl;
}
};
int main() {
Derived d;
Base* b = &d;
b->SetData( 10);
b->SetData("abc");
Derived::Param param;
d.SetData(param);
}実行結果: Derived (int) Derived (const char*) Derived (const Param&)
override の 追加 を 行っ た こと、 新規 で 追加 し た 関数 にだけ virtual を 付ける こと によって、 どの 関数 が オーバーライド さ れ た もの で、 どの 関数 が そう で ない もの かを 明確 に 区別 できる よう になり まし た。 安全 性 も 高まっ て い ます。
関数の削除 (C++11)
C ++ 11 で、 関数 の 定義 を 削除 する 機能 が 追加 さ れ まし た。 void f() = delete; この よう に 関数 宣言 の 末尾 に「= delete」 を 置く と、 その 関数 は 削除 さ れ ます。 削除 さ れ た 関数 を 呼び出し たり、 アドレス を 取得 し たり する コード を 書く と、 コンパイル エラー になり ます。「= delete」 の 代表的 な 利用 例 として、 オブジェクト の コピー を 禁止 する こと が 挙げ られ ます。
before (C++98/ 03)
C++03 以前 は、 コピーコンストラクタ や コピー 代入 演算子 を private に する こと によって、コピー を 禁止 し て い まし た。
class MyClass {
public:
MyClass() {}
private:
MyClass( const MyClass&);
MyClass& operator =( const MyClass&);
};
int main() {
MyClass a, b;
MyClass c(a); // コンパイル エラー
a = b; // コンパイル エラー
}この 方法 の 場合、 private に する だけで なく、 定義 も 書か ない こと が 重要 です。 定義 が ある と、 MyClass の メンバ 関数 からは 呼び出せ て しまい ます。 定義 を 書か なけれ ば、 呼び出そ う と し た とき に リンク エラー に でき ます。
after (C++11/ 14/ 17)
class MyClass {
public:
MyClass() {}
MyClass( const MyClass&) = delete;
MyClass& operator =( const MyClass&) = delete;
};
int main() {
MyClass a, b;
MyClass c(a); // コンパイル エラー
a = b; // コンパイル エラー
}こちら の 方 が 簡単 で 明確 です し、 C ++ 03 以前 の 方法 の よう に、 MyClass の 他 の メンバ 関数 からの 呼び出し に 注意 する 必要 も 無くなり ます。 削除 さ れ て いる 訳 です から、 friend の 利用 を 含め、 どんな 手段 を 使っ た として も 絶対 に 呼び出せ ませ ん。なお、 before の サンプル プログラム と 違っ て、 コピーコンストラクタ と コピー 代入 演算子 の 宣言 を、 public に 変更 し て い ます。 これ は 必須 という 訳 では あり ませ ん が、 public に し て おく こと で、 誤っ て これら の 関数 を 使お う と し た とき に、「 削除 さ れ て いる」 という 主旨 の コンパイル エラー を 出す こと が でき ます。 private に なっ て いる と、「 非公開 な 関数 に アクセス でき ない」 という 主旨 の エラー で 報告 さ れる 可能性 が あり、 関数 が 削除 さ れ て いる という 事実 が 伝わり づらく なり ます。


コメント