クラスの基本テンプレート

c++ の class は、最低限必要とするコンストラクタやメンバー関数がいろいろあります。
加えて "自動的に作成される特殊メンバ関数" なんてものがあり、さらに面倒なことに自動的に生成されるルールがあるため、自動生成されたり、自動生成されなかったりします。正直、お手本のソースコードでも用意しておかないと難しい内容です。

本ページでは、c++ の class の雛形を用意して、これをもとにして必要な修正を行うだけである程度のコーディングを行えるようにすることを目指します。

 

 

 

1. 暗黙定義される関数の default 指定(c++11)

クラスには、暗黙的に作成されるメンバ関数があります。以下がそれに該当します。

 

 

= default は、これらに対して以下のように明示的にデフォルトのものを使う指定ができます。

 

class S {
    S() = default;
}

 

クラスにコンストラクタが1つも宣言されていない場合、デフォルトコンストラクタ、コピーコンストラクタ、およびムーブコンストラクタが暗黙的に生成されます。しかし、コンストラクタが1つでも宣言されると、それらは暗黙的に生成されなくなります。 = default を用いることで、これらのメンバ関数を暗黙的に生成されたものと同じように生成できます。

 

 

2. 暗黙定義される関数の delete 指定(c++11)

= delete は、コンパイラが暗黙的に生成する特殊なメンバ関数の削除を指定します。例えば、コピーはできないがムーブは可能なクラス、は以下のように定義します。

 

class S {
    // コピーできない
    S(const S&) = delete;
    S& operator=(const S&) = delete;

    // ムーブは可能
    S(S&& s) {
        ・・・
    }
};

 

= delete は、特殊メンバ関数に対してだけでなく、通常の関数に対しても指定できます。その場合、delete 指定された関数オーバーロードが呼び出されると、コンパイルエラーになります。

 

 

 

3. 基本の class 表記 ("= default" 利用)

[概要]

一番シンプルであろうテンプレートを以下に示します。
c++11 以降を前提に、まずは default 指定で全て記載した例を示します。
"自動的に作成される特殊メンバ関数" を全て default 指定しているので、自動的に作成されるメンバ関数はありません。

 

[評価環境]

コンパイラ : g++, 13.3.0
OS : Ubuntu, 24.04

 

[プログラムソース "class_template_01.cpp"]

#include <utility>  // std::move

class Base {
public:
    Base() = default;                               // default constructor
    virtual ~Base() = default;                      // virtual destructor

    Base(const Base&) = default;                    // copy constructor
    Base& operator = (const Base&) = default;       // copy operator

    Base(Base&&) = default;                         // move constructor
    Base& operator = (Base&&) = default;            // move operator
};

int main()
{
    Base b1;                // call 'default constructor'.
    Base b2(b1);            // call 'copy constructor'.
    Base b3 = b2;           // call 'copy operator'.
    Base b4(Base{});        // call 'move constructor'.
    Base b5 = Base();       // call 'move operator'.
        
    Base b6;
    b6 = b1;                // call 'copy operator'.
    Base b7;
    b7 = std::move(b1);     // call 'move operator'.
    
    return 0;
}

 

下記コマンドでビルドします。

$ g++ -std=c++23 -Wall -Wextra -Wpedantic class_template_01.cpp -o class_template_01.out

 

実行結果は以下の通り・・・何も起こりません。残念ながらそういうプログラムです。

$ ./class_template_01.out
$

 

 

ちょっとだけプログラムを追加して、コピーやムーブしていることを確認してみたいと思います。

 

[プログラムソース "class_template_02.cpp"]

#include <utility>  // std::move
#include <string>
#include <iostream>

class Base {
public:
    std::string name = "default_name";

public:
    Base() = default;                               // default constructor
    virtual ~Base() = default;                      // virtual destructor

    Base(const Base&) = default;                    // copy constructor
    Base& operator = (const Base&) = default;       // copy operator

    Base(Base&&) = default;                         // move constructor
    Base& operator = (Base&&) = default;            // move operator
};

int main()
{
    Base b1;                // call 'default constructor'.
    b1.name = "b1";
    Base b2(b1);            // call 'copy constructor'.
    Base b3 = b2;           // call 'copy operator'.
    Base b4(Base{});        // call 'move constructor'.
    Base b5 = Base();       // call 'move operator'.
    
    Base b6;
    b6 = b1;                // call 'copy operator'.
    Base b7;
    b7 = std::move(b1);     // call 'move operator'.

    // 確認 
    std::cout << "b1.name: " << b1.name << std::endl;
    std::cout << "b2.name: " << b2.name << std::endl;
    std::cout << "b3.name: " << b3.name << std::endl;
    std::cout << "b4.name: " << b4.name << std::endl;
    std::cout << "b5.name: " << b5.name << std::endl;
    std::cout << "b6.name: " << b6.name << std::endl;
    std::cout << "b7.name: " << b7.name << std::endl;

    return 0;
}

 

下記コマンドでビルドします。

$ g++ -std=c++23 -Wall -Wextra -Wpedantic class_template_02.cpp -o class_template_02.out

 

実行結果を以下に記載します。

$ ./class_template_02.out
b1.name: 
b2.name: b1
b3.name: b1
b4.name: default_name
b5.name: default_name
b6.name: b1
b7.name: b1
$ 

 

厳密な確認ではないですが、期待通りに動作しているであろうことを確認できました。 

 

 

4. 基本の class 表記 ("= default" 無し)

[概要]

前章では、= default を積極利用して class を作ってみました。

本章では、同じ内容のプログラムを = default を使用せずに作成してみます。

 

[評価環境]

コンパイラ : g++, 13.3.0
OS : Ubuntu, 24.04

 

作成したプログラムを以下に記載します。

それなりに注意を要するプログラムであることがわかります。

 

[プログラムソース "class_template_03.cpp"]

#include <utility>  // std::move
#include <string>
#include <iostream>

class Base {
public:
    std::string name = "default_name";

public:
    // 明示的な default constructor(元の = default と同等)
    Base()
    {
    }

    // 明示的な virtual destructor
    virtual ~Base()
    {
    }

    // 明示的な copy constructor
    Base(const Base& other)
        : name(other.name)
    {
    }

    // 明示的な copy operator
    Base& operator=(const Base& other)
    {
        if (this != &other) {
            name = other.name;
        }
        return *this;
    }

    // 明示的な move constructor
    Base(Base&& other) noexcept
        : name(std::move(other.name))
    {
    }

    // 明示的な move operator
    Base& operator=(Base&& other) noexcept
    {
        if (this != &other) {
            name = std::move(other.name);
        }
        return *this;
    }
};

int main()
{
    Base b1;                // call 'default constructor'.
    b1.name = "b1";
    Base b2(b1);            // call 'copy constructor'.
    Base b3 = b2;           // call 'copy operator'.
    Base b4(Base{});        // call 'move constructor'.
    Base b5 = Base();       // call 'move operator'.
    
    Base b6;
    b6 = b1;                // call 'copy operator'.
    Base b7;
    b7 = std::move(b1);     // call 'move operator'.

    // 確認
    std::cout << "b1.name: " << b1.name << std::endl;
    std::cout << "b2.name: " << b2.name << std::endl;
    std::cout << "b3.name: " << b3.name << std::endl;
    std::cout << "b4.name: " << b4.name << std::endl;
    std::cout << "b5.name: " << b5.name << std::endl;
    std::cout << "b6.name: " << b6.name << std::endl;
    std::cout << "b7.name: " << b7.name << std::endl;

    return 0;
}

 

下記コマンドでビルドします。

$ g++ -std=c++23 -Wall -Wextra -Wpedantic class_template_03.cpp -o class_template_03.out

 

実行結果を以下に記載します。

$ ./class_template_03.out
b1.name: 
b2.name: b1
b3.name: b1
b4.name: default_name
b5.name: default_name
b6.name: b1
b7.name: b1
$ 

 

前章と同じ結果になることを確認できました。

 

 

ライセンス

本ページの情報は、特記無い限り下記 MIT ライセンスで提供されます。

The MIT License (MIT)

  Copyright 2025 Kinoshita Hidetoshi

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

 

 

参考

 


 

変更履歴

2025-11-06 - 新規作成

 

Programming Items トップページ

プライバシーポリシー