クラス宣言
From cppreference.com
クラスはユーザー定義型であり、宣言構文のdecl-specifier-seqに現れるclass-specifierによって定義されます。
目次 |
[編集] 構文
クラス指定子は以下の構文を持ちます。
class-key attr (省略可能) class-head-name class-property-specs (省略可能) base-clause (省略可能){ member-specification } |
(1) | ||||||||
class-key attr (省略可能) base-clause (省略可能){ member-specification } |
(2) | ||||||||
1) 名前付きクラス定義
2) 匿名クラス定義
| class-key | - | class、struct、unionのいずれか。classとstructキーワードは、デフォルトのメンバーアクセスとデフォルトの基底クラスアクセスを除いて同一です。unionの場合、この宣言は共用体型を導入します。 | ||||||||
| attr | - | (C++11以降) 任意の数の属性。alignas指定子を含むことができます。 | ||||||||
| class-head-name | - | 定義されているクラスの名前。修飾されることも可能です。 | ||||||||
| class-property-specs | - | 以下の指定子のリスト。各指定子は各シーケンスで最大1回まで許可されます。
| ||||||||
| base-clause | - | 1つ以上の基底クラスと、それぞれの継承モデルのリスト(派生クラスを参照)。 | ||||||||
| member-specification | - | アクセス指定子、メンバーオブジェクトおよびメンバー関数の宣言と定義のリスト(以下を参照)。 |
[編集] 前方宣言
以下の形式の宣言
class-key attr identifier ; |
|||||||||
後でこのスコープ内で定義されるクラス型を宣言します。定義が現れるまで、このクラス名は不完全型です。これにより、相互参照するクラスが可能になります。
class Vector; // forward declaration class Matrix { // ... friend Vector operator*(const Matrix&, const Vector&); }; class Vector { // ... friend Vector operator*(const Matrix&, const Vector&); };
特定のソースファイルがクラスへのポインタと参照のみを使用する場合、これにより#includeの依存関係を減らすことができます。
// In MyStruct.h #include <iosfwd> // contains forward declaration of std::ostream struct MyStruct { int value; friend std::ostream& operator<<(std::ostream& os, const S& s); // definition provided in MyStruct.cpp file which uses #include <ostream> };
前方宣言がローカルスコープに現れる場合、それは以前に宣言されたクラス、変数、関数、および囲むスコープに現れる可能性のある同じ名前の他のすべての宣言を隠蔽します。
struct s { int a; }; struct s; // does nothing (s already defined in this scope) void g() { struct s; // forward declaration of a new, local struct "s" // this hides global struct s until the end of this block s* p; // pointer to local struct s struct s { char* p; }; // definitions of the local struct s }
新しいクラス名は、別の宣言の一部として現れるelaborated type specifierによっても導入されうることに注意してください。ただし、その場合、名前検索が同じ名前で以前に宣言されたクラスを見つけられない場合に限ります。
class U; namespace ns { class Y f(class T p); // declares function ns::f and declares ns::T and ns::Y class U f(); // U refers to ::U // can use pointers and references to T and Y Y* p; T* q; }
[編集] メンバー仕様
メンバー仕様、またはクラス定義の本体は、以下の任意の数の波括弧で囲まれたシーケンスです。
1) 以下の形式のメンバー宣言
attr (省略可能) decl-specifier-seq (省略可能) member-declarator-list (省略可能) ; |
|||||||||
| attr | - | (C++11以降) 任意の数の属性 |
| decl-specifier-seq (宣言指定子シーケンス) | - | 指定子のシーケンス。コンストラクタ、デストラクタ、およびユーザー定義型変換関数の宣言でのみ省略可能です。 |
| member-declarator-list | - | init-declarator-listに似ていますが、追加でビットフィールド宣言、純粋指定子、およびvirt-specifier(overrideまたはfinal)(C++11以降)を許可し、direct-non-list-initialization構文は許可しません。 |
この宣言は、staticおよび非staticデータメンバー、メンバー関数、メンバーtypedef、メンバー列挙、およびネストされたクラスを宣言できます。また、フレンド宣言であることも可能です。
class S { int d1; // non-static data member int a[10] = {1, 2}; // non-static data member with initializer (C++11) static const int d2 = 1; // static data member with initializer virtual void f1(int) = 0; // pure virtual member function std::string d3, *d4, f2(int); // two data members and a member function enum { NORTH, SOUTH, EAST, WEST }; struct NestedS { std::string s; } d5, *d6; typedef NestedS value_type, *pointer_type; };
2) メンバー関数またはフレンド関数の両方を宣言および定義する関数定義。メンバー関数定義の後のセミコロンは省略可能です。クラス本体内で定義されるすべての関数は、inlineとなり、名前付きモジュールにアタッチされていない限り(C++20以降)。
class M { std::size_t C; std::vector<int> data; public: M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition int operator()(std::size_t r, std::size_t c) const // member function definition { return data[r * C + c]; } int& operator()(std::size_t r, std::size_t c) // another member function definition { return data[r * C + c]; } };
3) アクセス指定子
public:, protected:, および private:class S { public: S(); // public constructor S(const S&); // public copy constructor virtual ~S(); // public virtual destructor private: int* ptr; // private data member };
4) using-declaration
class Base { protected: int d; }; class Derived : public Base { public: using Base::d; // make Base's protected member d a public member of Derived using Base::Base; // inherit all bases' constructors (C++11) };
5)
static_assert 宣言template<typename T> struct Foo { static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point"); };
6) メンバーテンプレート宣言
struct S { template<typename T> void f(T&& n); template<class CharT> struct NestedS { std::basic_string<CharT> s; }; };
| (C++11以降) |
|
8) メンバークラステンプレートの推論ガイド
struct S { template<class CharT> struct NestedS { std::basic_string<CharT> s; }; template<class CharT> NestedS(std::basic_string<CharT>) -> NestedS<CharT>; }; |
(C++17以降) |
|
9) using-enum-declaration
enum class color { red, orange, yellow }; struct highlight { using enum color; }; |
(C++20以降) |
[編集] ローカルクラス
クラス宣言は関数本体の内部に現れることができ、その場合、それはローカルクラスを定義します。そのようなクラスの名前は関数スコープ内でのみ存在し、外部からはアクセスできません。
- ローカルクラスのメンバーは、そのクラスの定義内でのみ宣言できます。ただし、ネストされたクラスであるメンバーは、そのクラスの最も近い囲むブロックスコープ内でも宣言できます。
- ローカルクラス内にネストされたクラスもローカルクラスです。
- ローカルクラスは静的データメンバーを持つことができません。
- ローカルクラスのメンバー関数はリンケージを持ちません。
- ローカルクラスのメンバー関数は、クラス本体内で完全に定義されなければなりません。
- ローカルクラスは、クロージャ型を除く(C++14以降)、メンバーテンプレートを持つことができません。
- ローカルクラスはフレンドテンプレートを持つことができません。
- ローカルクラスは、クラス定義内でフレンド関数を定義できません。
- 関数(メンバー関数を含む)内のローカルクラスは、囲む関数がアクセスできるのと同じ名前にアクセスできます。
|
(C++11まで) |
このコードを実行
#include <algorithm> #include <iostream> #include <vector> int main() { std::vector<int> v{1, 2, 3}; struct Local { bool operator()(int n, int m) { return n > m; } }; std::sort(v.begin(), v.end(), Local()); // since C++11 for (int n : v) std::cout << n << ' '; std::cout << '\n'; }
出力
3 2 1
[編集] キーワード
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 1693 | C++98 | メンバー宣言は空であってはいけません | 空の宣言が許可されました |
| CWG 1930 | C++98 | decl-specifier-seqがストレージクラス指定子またはcv修飾子を含む場合、member-declarator-listは空であってもよい ストレージクラス指定子またはcv修飾子を含む場合 |
リストは空であってはなりません |
| CWG 2890 | C++98 | ネストされたクラスのメンバーがどこで宣言できるかが不明瞭でした | 明確化された |
[編集] 関連項目
| C ドキュメント(構造体宣言について)
|