0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【C++】クラス

Last updated at Posted at 2024-12-16

オブジェクト指向(※超重要)

  • オブジェクト指向とは
    現実世界の「物」や「概念」を、特徴(名前、年齢など)を変数にしたものと
    動作(移動する、話すなど)を関数にしたものをまとめたもの(オブジェクト)に対して、
    指示を送ること(指向)でオブジェクト間の関係の定義や動作をさせる考え方。

クラス(※抽象的に説明します)

クラスはオブジェクト指向の「オブジェクト」の設計図
とりあえず、構造体に関数を加えたものと考えればOK!

構造体と比較して、異なる部分の確認

C++

構造体.h
#ifndef 構造体_H_INCLUDED
#define 構造体_H_INCLUDED

#include <iostream>
#include <string> // C++の文字列型
#include <format>

struct BaseInformation
{
	std::string name; // 名前
	int age;		  // 年齢
};

/// <summary>
/// 基本情報を出力する
/// </summary>
void PrintInformation(BaseInformation& baseInformation)
{
	std::cout << std::format("{}は{}歳です", baseInformation.name, baseInformation.age) << std::endl;
}

/// <summary>
/// 基本情報を出力する
/// </summary>
void InputInformation(BaseInformation& baseInformation)
{
	std::cout << "名前を入力してください" << std::endl;
	std::cin >> baseInformation.name;
	std::cout << "年齢を入力してください" << std::endl;
	std::cin >> baseInformation.age;
}

#endif // !構造体_H_INCLUDED
クラス.h
#ifndef クラス_H_INCLUDED
#define クラス_H_INCLUDED

#include<iostream>
#include<string> // C++の文字列型

class BaseInformationClass
{
	/// <summary>
	/// 基本情報を出力する
	/// </summary>
	void PrintInformation(void)
	{
		std::cout << std::format("{}は{}歳です", name, age) << std::endl;
	}

	/// <summary>
	/// 基本情報を入力する
	/// </summary>
	void InputInformation(void)
	{
		std::cout << "名前を入力してください" << std::endl;
		std::cin >> name;
		std::cout << "年齢を入力してください" << std::endl;
		std::cin >> age;
	}

	std::string name; // 名前
	int age;		  // 年齢
};

#endif // !クラス_H_INCLUDED
example.cpp
#include "構造体.h"
#include "クラス.h"

int main()
{
#if 1 // 1 = 構造体、0 = クラス
	BaseInformation baseInformation = { "自分の名前", 104 };

	InputInformation(baseInformation);
	PrintInformation(baseInformation);
#else
    // C#では、 = new BaseInformationClass("自分の名前", 104);になる
	BaseInformationClass baseInformationClass = { "自分の名前", 104 };

	baseInformationClass.InputInformation();
	baseInformationClass.PrintInformation();
#endif

	return 0;
}

C#

example.cs
using System;

struct BaseInformation
{
	public string name; // 名前
    public int age;     // 年齢
};

/// <summary>
/// 基本情報を出力する
/// </summary>
static void PrintInformation(BaseInformation baseInformation)
{
    Console.WriteLine($"{baseInformation.name}{baseInformation.age}歳です");
}

/// <summary>
/// 基本情報を入力する
/// </summary>
static void InputInformation(ref BaseInformation baseInformation)
{
    Console.Write("名前を入力してください: ");
    baseInformation.name = Console.ReadLine();

    Console.Write("年齢を入力してください: ");
    baseInformation.age = int.TryParse(Console.ReadLine());
}

public class BaseInformationClass
{
    string name;
    int age;

    /// <summary>
    /// 基本情報を出力する
    /// </summary>
    void PrintInformation()
    {
        Console.WriteLine($"{name}{age}歳です");
    }

    /// <summary>
    /// 基本情報を入力する
    /// </summary>
    void InputInformation()
    {
        Console.Write("名前を入力してください: ");
        name = Console.ReadLine();
        Console.Write("年齢を入力してください: ");
        age = int.Parse(Console.ReadLine());
    }
}

static int Main(string[] args)
{
    #if 1 // 1 = 構造体、0 = クラス
    	BaseInformation baseInformation = new BaseInformation { name = "自分の名前", age = 104 };

        InputInformation(ref baseInformation);
        PrintInformation(baseInformation);
    #else
    	BaseInformationClass baseInformationClass = new BaseInformationClass("自分の名前", 104 };

    	baseInformationClass.InputInformation();
    	baseInformationClass.PrintInformation();
    #endif
}

クラスの方では以下のエラーが

  • コンストラクターのインスタンスが引数リストと一致しません
  • 関数にアクセスできません

これを解決するには?...

コンストラクタ

  • 備考
    クラスが生成された際に自動で呼び出される関数
    関数名はクラスと同名、戻り値はなしで、引数はオーバーロード可能
    ※コンストラクタ内でメンバ変数は必ず初期化
class BaseInformationClass
{
    // コンストラクタ
    BaseInformationClass()
    {
        name = "";
        age = 0;
    }

        
        
        
};

デストラクタ

  • 備考
    クラスが破棄された際に自動で呼び出される関数
    関数名はクラス名の前に ~ (チルダ)をつけ、戻り値はなしで、引数はオーバーロード可能
class BaseInformationClass
{
    // デストラクタ
    ~BaseInformationClass()
    {

    }

        
        
        
};

default

用途 : 特殊メンバ関数が不必要であること(処理がないこと)を明示化

class Example
{
    Example() = default;
    ~Example() = default;
}

delete

用途 : 特殊メンバ関数の使用を禁止(主にコピーコンストラクタとコピー演算子に使う)

class Example
{
    Example(const Example& other) = delete;
    Example& operator=(const Example& other) = delete;
}

特殊メンバ関数

備考 : クラスのオブジェクトが生成、コピー、破棄される際に自動的に呼び出される

class Example
{
public:
	/// <summary>
	/// コンストラクタ
	/// </summary>
	Example();

	/// <summary>
	/// デストラクタ
	/// </summary>
	~Example();

	/// <summary>
	/// コピーコンストラクタ
	/// 
	/// 既存のオブジェクトをコピーして、新しいオブジェクトを作成する
	/// </summary>
	/// <param name="other">コピー元のconst参照</param>
	Example(const Example& other);


	/// <summary>
	/// コピー代入演算子
	/// 
	/// =を使って、既存のオブジェクトをコピーして、値を代入する
	/// </summary>
	/// <param name="other">コピー元のconst参照</param>
	Example& operator=(const Example& other);

	/// <summary>
	/// ムーブコンストラクタ
	/// 
	/// 既存のオブジェクトから新しいオブジェクトに、リソースを移動する
    /// noexcept : この関数が例外を投げないことを意味する
	/// </summary>
	/// <param name="other">コピー元のオブジェクトの右値参照(&&)</param>
	Example(Example&& other) noexcept;

	/// <summary>
	/// ムーブ代入演算子
	/// 
	/// =を使って、既存のオブジェクトから新しいオブジェクトに、リソースを代入する
    /// noexcept : この関数が例外を投げないことを意味する
	/// </summary>
	/// <param name="other">コピー元のオブジェクトの右値参照(&&)</param>
	Example& operator=(Example&& other) noexcept;
};
 

アクセス指定子(C++)

用途 : クラスのメンバ(クラス内の変数や関数)へ、クラス外からアクセスできるかを指定する

public: : クラス外からアクセスできる
private: : クラス外からアクセスできない

クラス.h
#ifndef クラス_H_INCLUDED
#define クラス_H_INCLUDED

#include<iostream>
#include<string> // C++の文字列型

class BaseInformationClass
{
public:
    // コンストラクタ
    BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // デストラクタ
    ~BaseInformationClass() = default;

	/// <summary>
	/// 基本情報を出力する
	/// </summary>
	void PrintInformation(void)
	{
		std::cout << std::format("{}は{}歳です", name, age) << std::endl;
	}

	/// <summary>
	/// 基本情報を入力する
	/// </summary>
	void InputInformation(void)
	{
		std::cout << "名前を入力してください" << std::endl;
		std::cin >> name;
		std::cout << "年齢を入力してください" << std::endl;
		std::cin >> age;
	}

	std::string name; // 名前
	int age;		  // 年齢
};

#endif // !クラス_H_INCLUDED

構造体はデフォルトの設定がpublic
クラスはデフォルトの設定がprivate

アクセス修飾子(C#)

アクセス指定子との違い : メンバ変数やメンバ関数ひとつひとつを指定する

public class BaseInformationClass
{
    string name;
    int age;

    // コンストラクタ
    public BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // デストラクタ
    public ~BaseInformationClass()
    {

    }

    /// <summary>
    /// 基本情報を出力する
    /// </summary>
    public void PrintInformation()
    {
        Console.WriteLine($"{name}{age}歳です");
    }

    /// <summary>
    /// 基本情報を入力する
    /// </summary>
    public void InputInformation()
    {
        Console.Write("名前を入力してください: ");
        name = Console.ReadLine();
        Console.Write("年齢を入力してください: ");
        age = int.Parse(Console.ReadLine());
    }
}

関数にアクセスできないエラーは解決!!
では、次。

thisポインタ(C++)

用途 : メンバ変数と同名の引数を扱う際に、メンバ変数にthis->をつけ区別する

クラス.h
#ifndef クラス_H_INCLUDED
#define クラス_H_INCLUDED

#include<iostream>
#include<string> // C++の文字列型

class BaseInformationClass
{
public:
    // コンストラクタ
    BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // コンストラクタのオーバーロード
    BaseInformationClass(std::string name, int age)
    {
        this->name = name;
        this->age = age;
    }

    // デストラクタ
    ~BaseInformationClass() = default;

	/// <summary>
	/// 基本情報を出力する
	/// </summary>
	void PrintInformation(void)
	{
		std::cout << std::format("{}は{}歳です", name, age) << std::endl;
	}

	/// <summary>
	/// 基本情報を入力する
	/// </summary>
	void InputInformation(void)
	{
		std::cout << "名前を入力してください" << std::endl;
		std::cin >> name;
		std::cout << "年齢を入力してください" << std::endl;
		std::cin >> age;
	}

	std::string name; // 名前
	int age;		  // 年齢
};

#endif // !クラス_H_INCLUDED

thisキーワード(C#)

  • thisポインタとの違い
    thisポインタ : オブジェクトのアドレスを指すポインタ
    thisキーワード : オブジェクト自身
public class BaseInformationClass
{
    string name;
    int age;

    // コンストラクタ
    public BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // コンストラクタのオーバーロード
    public BaseInformationClass(string name, int age)
    {
        this.name = name;
        this.age = age;
    }

    // デストラクタ
    public ~BaseInformationClass()
    {

    }

    /// <summary>
    /// 基本情報を出力する
    /// </summary>
    public void PrintInformation()
    {
        Console.WriteLine($"{name}{age}歳です");
    }

    /// <summary>
    /// 基本情報を入力する
    /// </summary>
    public void InputInformation()
    {
        Console.Write("名前を入力してください: ");
        name = Console.ReadLine();
        Console.Write("年齢を入力してください: ");
        age = int.Parse(Console.ReadLine());
    }
}

thisの有用性

ここまで解説しましたが、かなり賛否両論な機能です。
なぜなら、thisを付け忘れ、バグとなり、
かつバグの中でも見つけにくいものに部類されるからです。
なので、thisを使わず、引数名の前に_(アンダーバー)をつけ、
区別するエンジニアが多いです。

メンバイニシャライザ(C++)

用途 : constメンバ変数、 参照メンバ変数の初期化

メンバイニシャライザは{}内で初期化するよりも、速いタイミングで初期化を行う

// コンストラクタのオーバーロード
BaseInformationClass(std::string _name, int _age)
	: name(_name), age(_age)
{}

完成?

構造体と同じ様に動くようになったので、これで解決なんですが...

カプセル化(※超重要)

用途 : データの安全性の確保、コードの保守性向上、再利用性の向上
備考 : クラスの三大要素(カプセル化、継承、多態性)の1つ。

C++

クラス.h
#ifndef クラス_H_INCLUDED
#define クラス_H_INCLUDED

#include<iostream>
#include<string> // C++の文字列型

class BaseInformationClass
{
public:
    // コンストラクタ
    BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // コンストラクタのオーバーロード
    BaseInformationClass(std::string _name, int _age)
    {
        name = _name;
        age = _age;
    }

    // デストラクタ
    ~BaseInformationClass() = default;

	/// <summary>
	/// 基本情報を出力する
	/// </summary>
	void PrintInformation(void)
	{
		std::cout << std::format("{}は{}歳です", name, age) << std::endl;
	}

	/// <summary>
	/// 基本情報を入力する
	/// </summary>
	void InputInformation(void)
	{
		std::cout << "名前を入力してください" << std::endl;
		std::cin >> name;
		std::cout << "年齢を入力してください" << std::endl;
		std::cin >> age;
	}

private:
	std::string name; // 名前
	int age;		  // 年齢
};

#endif // !クラス_H_INCLUDED

C#

public class BaseInformationClass
{
    private string name; // 名前
    private int age;     // 年齢

    // コンストラクタ
    public BaseInformationClass()
    {
        name = "";
        age = 0;
    }

    // コンストラクタのオーバーロード
    public BaseInformationClass(string _name, int _age)
    {
        name = _name;
        age = _age;
    }

    // デストラクタ
    public ~BaseInformationClass()
    {

    }

    /// <summary>
    /// 基本情報を出力する
    /// </summary>
    public void PrintInformation()
    {
        Console.WriteLine($"{name}{age}歳です");
    }

    /// <summary>
    /// 基本情報を入力する
    /// </summary>
    public void InputInformation()
    {
        Console.Write("名前を入力してください: ");
        name = Console.ReadLine();
        Console.Write("年齢を入力してください: ");
        age = int.Parse(Console.ReadLine());
    }
}

ゲッター(Get〇〇)、セッター(Set〇〇)

用途 : privateのメンバ変数を取得や変更

C++

public:

// 名前の取得・変更
inline std::string GetName(void) { return name; }
inline void SetName(std::string _name) { name = _name; }

// 年齢の取得・変更
inline int GetAge(void) { return age; }
inline void SetAge(int _age) { age = _age; }

C#

// 名前の取得・変更
public string Name()
{
    get { return name; }
    set { name = value; }
}

// 年齢の取得・変更
public int Age()
{
    get { return age; }
    set { age = value; }
}

constメンバ関数(C++)

用途 : 関数内で値の変更を不可能にする

C++

public:

// 名前の取得
inline std::string GetName(void) const { return name; }

// 年齢の取得
inline int GetAge(void) const { return age; }

静的メンバ

用途 : インスタンス生成の省略(クラス全体で共有)

静的メンバ変数と静的メンバ関数

C++

example.cpp
#include <iostream>

class Example
{
public:
	/// <summary>
	/// 静的メンバ関数
	/// </summary>
	inline static int GetAddNumber(int number2)
	{
		return number + number2;
	}

private:
	static int number; // 静的メンバ変数
};
// 静的メンバ変数の初期化
int Example::number = 0;

int main()
{
	// 出力
	printf("%d\n", Example::GetAddNumber(10));

	return 0;
}

C#

example.cs
using System;

public class Example
{
    private static int number = 0; // 静的メンバ変数

	/// <summary>
	/// 静的メンバ関数
	/// </summary>
	public static int GetAddNumber(int number2)
	{
		return number + number2;
	}
};

static int Main(string[] args)
{
    Console.WriteLine($"{Example.GetAddNumber(10)}");
}

注意点

  1. 静的メンバ変数はクラス外で初期化(C++)
    (クラスが呼び出された時、その度に初期化されるため)
  2. 静的メンバ関数内では静的メンバ変数または引数のみ使用可能
    また、thisは使用できない
    (インスタンスを生成しないため)
0
0
1

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?