C++は、オブジェクト指向プログラミング言語として広く利用されています。その中でも、アクセス指定子と仮想関数テーブル(vtable)は重要な概念です。本記事では、C++のアクセス指定子(public、private、protected)と仮想関数テーブルの基本と応用を詳しく解説し、プログラミングの理解を深める手助けをします。
アクセス指定子とは
C++のアクセス指定子は、クラスのメンバー(変数や関数)のアクセス権を制御するために使用されます。主なアクセス指定子にはpublic、private、protectedがあります。これらの指定子を使うことで、クラスの設計においてメンバーの可視性とアクセスレベルを明確に定義することができます。アクセス指定子は、クラスのカプセル化を実現し、データの不正な操作を防ぐために重要な役割を果たします。
public
public指定子を使うと、クラス外部からもメンバーにアクセスできます。これは、インターフェースを提供するために使用されます。
private
private指定子を使うと、クラス内部からのみメンバーにアクセスできます。外部からの直接アクセスを防ぎ、データの安全性を保ちます。
protected
protected指定子を使うと、クラス内部および派生クラスからアクセスできます。継承関係において、派生クラスに対してメンバーを公開するために使用されます。
publicの使い方と特徴
public指定子を使用すると、クラスのメンバーがクラス外部からもアクセス可能になります。これにより、オブジェクトのインターフェースを定義し、クラスのユーザーがメンバーに直接アクセスして操作できるようにします。主に、クラスのメソッドや変数を外部に公開する場合に使用されます。
publicの使用例
以下は、public指定子を使用した基本的なクラスの例です:
class MyClass {
public:
int publicVariable;
void publicMethod() {
// メソッドの処理
}
};
この例では、publicVariable
およびpublicMethod
はクラスの外部からアクセス可能です。
publicの特徴と注意点
- アクセスの自由度: publicメンバーはクラス外部から自由にアクセスできます。
- インターフェースの提供: クラスの機能を外部に提供するためのインターフェースを構築します。
- 安全性の低下: 誤って不正な操作が行われるリスクがあるため、適切に設計しないと安全性が低下します。
適切な使用シチュエーション
- インターフェースの公開: クラスの機能を外部に提供する場合。
- 外部からのデータ操作が必要な場合: クラスの内部データを外部から操作する必要がある場合。
public指定子を適切に使用することで、クラスのインターフェースを明確にし、プログラムの可読性と使いやすさを向上させることができます。ただし、安全性に配慮し、公開するメンバーを慎重に選ぶことが重要です。
privateの使い方と特徴
private指定子を使用すると、クラスのメンバーがクラス内部からのみアクセス可能になります。これにより、クラスの外部からの直接アクセスを防ぎ、データのカプセル化と保護を実現します。クラス内部の実装詳細を隠蔽し、インターフェースを通じてのみ操作させることで、誤った操作や不正なアクセスからデータを守ることができます。
privateの使用例
以下は、private指定子を使用した基本的なクラスの例です:
class MyClass {
private:
int privateVariable;
void privateMethod() {
// メソッドの処理
}
public:
void setVariable(int value) {
privateVariable = value;
}
int getVariable() {
return privateVariable;
}
};
この例では、privateVariable
およびprivateMethod
はクラスの外部からアクセスできませんが、setVariable
およびgetVariable
を通じて間接的に操作できます。
privateの特徴と注意点
- データのカプセル化: クラスの内部データを隠蔽し、外部からの不正なアクセスを防ぎます。
- 安全性の向上: 重要なデータや内部実装を保護し、誤った操作による問題を減少させます。
- 制約の管理: クラスの使用方法を制限し、設計者が意図した方法でのみ使用されるようにします。
適切な使用シチュエーション
- データの保護: クラス内部の重要なデータを保護する必要がある場合。
- 内部実装の隠蔽: 外部に公開したくないメソッドや変数を隠蔽する場合。
- インターフェースの制御: 外部からの操作を制限し、特定の操作のみを許可する場合。
private指定子を適切に使用することで、クラスの安全性と信頼性を向上させることができます。内部データの保護とカプセル化を実現するために、慎重に設計しましょう。
protectedの使い方と特徴
protected指定子を使用すると、クラスのメンバーがクラス内部および派生クラスからアクセス可能になります。これは、継承を利用する際に非常に便利で、基底クラスのメンバーを派生クラスで利用することができますが、クラスの外部からはアクセスできません。これにより、オブジェクト指向の特性である再利用性と拡張性を高めることができます。
protectedの使用例
以下は、protected指定子を使用した基本的なクラスの例です:
class BaseClass {
protected:
int protectedVariable;
void protectedMethod() {
// メソッドの処理
}
};
class DerivedClass : public BaseClass {
public:
void useProtectedMembers() {
protectedVariable = 10; // 派生クラスからアクセス可能
protectedMethod(); // 派生クラスからアクセス可能
}
};
この例では、protectedVariable
およびprotectedMethod
は基底クラスとその派生クラス内でアクセスできますが、クラスの外部からはアクセスできません。
protectedの特徴と注意点
- 継承における利便性: protectedメンバーは、基底クラスから派生クラスへアクセスを許可します。
- データのカプセル化と共有: クラス間で共通のデータやメソッドを共有しながら、外部からのアクセスを防ぎます。
- 安全性の確保: クラスの外部からの直接アクセスを防ぎつつ、継承関係における柔軟性を提供します。
適切な使用シチュエーション
- 継承関係の管理: 基底クラスのメンバーを派生クラスで使用する場合。
- クラス間のデータ共有: 継承関係にあるクラス間でデータやメソッドを共有する必要がある場合。
- カプセル化の維持: 外部からのアクセスを防ぎつつ、継承関係における柔軟性を持たせる場合。
protected指定子を適切に使用することで、クラスの設計における柔軟性と安全性を両立させることができます。継承を利用する際には、protectedメンバーを効果的に活用し、コードの再利用性とメンテナンス性を向上させましょう。
アクセス指定子の実用例
アクセス指定子を使った実際のコーディング例を通じて、各指定子の役割と使用方法を理解します。以下に、public、private、protectedの各指定子を利用したクラスの具体例を示します。
実用例: BankAccountクラス
この例では、BankAccount
クラスを定義し、各アクセス指定子を用いてメンバーの可視性とアクセス制御を行います。
#include <iostream>
#include <string>
class BankAccount {
private:
std::string accountNumber;
double balance;
protected:
std::string ownerName;
public:
BankAccount(std::string owner, std::string accountNum, double initialBalance)
: ownerName(owner), accountNumber(accountNum), balance(initialBalance) {}
void deposit(double amount) {
balance += amount;
std::cout << "Deposited: " << amount << ", New Balance: " << balance << std::endl;
}
void withdraw(double amount) {
if (amount <= balance) {
balance -= amount;
std::cout << "Withdrew: " << amount << ", New Balance: " << balance << std::endl;
} else {
std::cout << "Insufficient funds" << std::endl;
}
}
void displayAccountInfo() {
std::cout << "Owner: " << ownerName << ", Account Number: " << accountNumber << ", Balance: " << balance << std::endl;
}
};
class SavingsAccount : public BankAccount {
private:
double interestRate;
public:
SavingsAccount(std::string owner, std::string accountNum, double initialBalance, double rate)
: BankAccount(owner, accountNum, initialBalance), interestRate(rate) {}
void applyInterest() {
double interest = balance * (interestRate / 100);
deposit(interest);
std::cout << "Interest Applied: " << interest << ", New Balance: " << balance << std::endl;
}
};
int main() {
SavingsAccount myAccount("John Doe", "123456789", 1000.0, 1.5);
myAccount.displayAccountInfo();
myAccount.deposit(200.0);
myAccount.withdraw(100.0);
myAccount.applyInterest();
return 0;
}
コード解説
- privateメンバー:
accountNumber
とbalance
はprivateとして宣言され、BankAccount
クラス内でのみアクセス可能です。
- protectedメンバー:
ownerName
はprotectedとして宣言され、派生クラスであるSavingsAccount
クラスでもアクセス可能です。
- publicメンバー:
deposit
、withdraw
、displayAccountInfo
などのメソッドはpublicとして宣言され、クラス外部からアクセス可能です。
この例では、アクセス指定子を適切に使用することで、データのカプセル化を実現しつつ、必要なインターフェースを提供しています。クラスの内部構造を隠蔽しながら、外部に必要な機能を公開することで、安全で柔軟なクラス設計が可能となります。
仮想関数とは
仮想関数は、C++におけるポリモーフィズムを実現するための重要な機能です。仮想関数を使用することで、基底クラスのポインタや参照を使って派生クラスのメソッドを呼び出すことができます。これにより、動的バインディングが可能となり、オブジェクト指向プログラミングの柔軟性が向上します。
仮想関数の定義
仮想関数は、基底クラスでvirtual
キーワードを使って宣言されます。派生クラスでは、この仮想関数をオーバーライドして独自の実装を提供します。
class Base {
public:
virtual void show() {
std::cout << "Base class show function" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class show function" << std::endl;
}
};
この例では、Base
クラスに仮想関数show
が定義され、Derived
クラスでオーバーライドされています。
仮想関数の使用例
以下は、仮想関数を使って基底クラスのポインタを通じて派生クラスのメソッドを呼び出す例です:
int main() {
Base *b;
Derived d;
b = &d;
b->show(); // Derived class show function
return 0;
}
このコードでは、Base
クラスのポインタb
をDerived
クラスのオブジェクトd
に指し、b->show()
を呼び出すことで派生クラスのshow
メソッドが実行されます。
仮想関数の特徴と利点
- 動的バインディング: 実行時に適切なメソッドが選択されるため、柔軟なプログラミングが可能になります。
- ポリモーフィズム: 基底クラスのポインタや参照を使って派生クラスのメソッドを呼び出すことができ、コードの再利用性が高まります。
- 拡張性: 新しい派生クラスを追加しても、既存のコードを変更せずに機能を拡張できます。
注意点
- パフォーマンスの影響: 仮想関数の呼び出しには若干のオーバーヘッドが発生しますが、ほとんどのケースで問題にはなりません。
- オーバーライドの確認: 派生クラスで仮想関数をオーバーライドする際には、
override
キーワードを使用して明示的に指定することで、誤ったオーバーライドを防ぐことができます。
仮想関数を適切に使用することで、C++プログラムにおいて柔軟性と拡張性を持たせることができます。動的バインディングを活用し、ポリモーフィズムを実現することで、より保守性の高いコードを書くことができます。
vtableの仕組み
仮想関数テーブル(vtable)は、C++における仮想関数の実装をサポートするための内部的なデータ構造です。vtableは、仮想関数を持つクラスごとに生成され、そのクラスのすべての仮想関数のアドレスを格納します。オブジェクトのメモリにはvtableへのポインタが含まれ、これを利用して動的バインディングを実現します。
vtableの基本構造
vtableは、各クラスに対して1つ作成され、そのクラスのすべての仮想関数のポインタを含みます。派生クラスは、基底クラスのvtableを継承し、オーバーライドされた仮想関数のポインタを更新します。
class Base {
public:
virtual void show() {
std::cout << "Base class show function" << std::endl;
}
};
class Derived : public Base {
public:
void show() override {
std::cout << "Derived class show function" << std::endl;
}
};
この例では、Base
クラスとDerived
クラスそれぞれに対応するvtableが存在し、Derived
クラスのvtableはshow
関数のアドレスをDerived
クラスの実装に置き換えます。
vtableの動作原理
オブジェクトには、vtableへのポインタが含まれます。このポインタを通じて、適切な仮想関数のアドレスが参照され、動的に関数が呼び出されます。
int main() {
Base *b;
Derived d;
b = &d;
b->show(); // Derived class show function
return 0;
}
このコードでは、b->show()
が呼び出されると、b
のvtableポインタを通じて、Derived
クラスのshow
関数が実行されます。
vtableの利点と影響
- 動的バインディングの実現: vtableを使用することで、実行時に適切な関数が動的に選択され、オブジェクト指向プログラミングの柔軟性が高まります。
- コードの拡張性: 新しい派生クラスを追加する際に、基底クラスのコードを変更せずに機能を拡張できます。
- パフォーマンスへの影響: vtableの使用により、関数呼び出しのオーバーヘッドが若干増加しますが、通常のアプリケーションでは無視できる程度です。
実装上の注意点
- vtableの生成: コンパイラが自動的にvtableを生成しますが、明示的に理解しておくことでデバッグやパフォーマンスチューニングが容易になります。
- メモリの使用: vtableのポインタは各オブジェクトに存在するため、大量のオブジェクトを扱う場合にはメモリ使用量に注意が必要です。
vtableは、C++における動的バインディングとポリモーフィズムを支える重要な仕組みです。これを理解することで、より高度なオブジェクト指向プログラミングが可能となります。
仮想関数とvtableの実用例
仮想関数とvtableを利用した具体的なコーディング例を通じて、これらの仕組みの実際の使い方を理解します。以下の例では、動物の鳴き声を表現するためのクラス階層を作成し、基底クラスのポインタを使って派生クラスのメソッドを呼び出します。
実用例: Animalクラスとその派生クラス
この例では、Animal
クラスを基底クラスとし、Dog
クラスとCat
クラスを派生クラスとして定義します。それぞれのクラスで仮想関数makeSound
を実装します。
#include <iostream>
class Animal {
public:
virtual void makeSound() {
std::cout << "Some generic animal sound" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
std::cout << "Woof! Woof!" << std::endl;
}
};
class Cat : public Animal {
public:
void makeSound() override {
std::cout << "Meow! Meow!" << std::endl;
}
};
void describeAnimalSound(Animal* animal) {
animal->makeSound();
}
int main() {
Dog dog;
Cat cat;
Animal* animal1 = &dog;
Animal* animal2 = &cat;
describeAnimalSound(animal1); // Woof! Woof!
describeAnimalSound(animal2); // Meow! Meow!
return 0;
}
コード解説
- 基底クラス
Animal
:
- 仮想関数
makeSound
を定義し、一般的な動物の鳴き声を出力します。
- 派生クラス
Dog
:
makeSound
をオーバーライドし、犬の鳴き声を出力します。
- 派生クラス
Cat
:
makeSound
をオーバーライドし、猫の鳴き声を出力します。
describeAnimalSound
関数は、Animal
クラスのポインタを引数として受け取り、そのポインタを使ってmakeSound
メソッドを呼び出します。実行時には、適切な派生クラスのメソッドが呼び出され、動的バインディングが実現されます。
vtableの動作確認
仮想関数を使用することで、animal->makeSound()
が実行時に適切なメソッドを呼び出すようになります。これは、オブジェクトが持つvtableポインタを通じて、正しい関数のアドレスが動的に選択されるためです。
実用例のメリット
- 柔軟性: 基底クラスのポインタを使うことで、異なる派生クラスのオブジェクトを同じインターフェースで操作できます。
- コードの再利用: 基底クラスと派生クラスの構造を利用して、コードの再利用性が向上します。
- メンテナンス性: 新しい動物クラスを追加する際にも、既存のコードを変更せずに拡張できます。
このように、仮想関数とvtableを利用することで、C++プログラムにおいて柔軟性と拡張性を持たせることができます。動的バインディングを活用することで、ポリモーフィズムを実現し、オブジェクト指向プログラミングの利点を最大限に引き出すことができます。
アクセス指定子とvtableの関係
アクセス指定子と仮想関数テーブル(vtable)は、C++のオブジェクト指向プログラミングにおいて重要な役割を果たしますが、これらがどのように相互作用するのかを理解することも重要です。特に、アクセス指定子がvtableにどのように影響を与えるかを詳しく見ていきます。
アクセス指定子と仮想関数
アクセス指定子(public、protected、private)は、クラスメンバーへのアクセス権を制御しますが、仮想関数にも適用されます。以下の例で、アクセス指定子が仮想関数にどのように影響するかを確認します。
class Base {
public:
virtual void publicMethod() {
std::cout << "Base public method" << std::endl;
}
protected:
virtual void protectedMethod() {
std::cout << "Base protected method" << std::endl;
}
private:
virtual void privateMethod() {
std::cout << "Base private method" << std::endl;
}
};
class Derived : public Base {
public:
void publicMethod() override {
std::cout << "Derived public method" << std::endl;
}
protected:
void protectedMethod() override {
std::cout << "Derived protected method" << std::endl;
}
private:
void privateMethod() override {
std::cout << "Derived private method" << std::endl;
}
};
この例では、Base
クラスにpublic、protected、privateの仮想関数が定義され、それぞれがDerived
クラスでオーバーライドされています。
vtableの構成
アクセス指定子に関係なく、仮想関数はvtableにエントリを持ちます。ただし、アクセス指定子は、関数がどこからアクセス可能かを制御します。
- public仮想関数: クラスの外部からもアクセス可能で、vtableにそのポインタが格納されます。
- protected仮想関数: クラスの外部からはアクセスできませんが、派生クラスからはアクセス可能です。これもvtableに格納されます。
- private仮想関数: クラスの外部および派生クラスからも直接アクセスできませんが、vtableには含まれます。
アクセス制御の影響
アクセス指定子は、vtableの構造には影響を与えませんが、関数のアクセス権を制御します。以下に、その影響をまとめます:
- public仮想関数:
- vtableに格納され、クラスの外部からもアクセス可能。
- protected仮想関数:
- vtableに格納され、派生クラスからアクセス可能。
- private仮想関数:
- vtableに格納され、派生クラスからはアクセス不可(ただし、vtableには存在)。
コードの実行例と注意点
以下のコードで、各関数の呼び出し例を示します:
int main() {
Derived d;
Base* b = &d;
b->publicMethod(); // Derived public method
// b->protectedMethod(); // エラー: protectedメソッドにはアクセスできない
// b->privateMethod(); // エラー: privateメソッドにはアクセスできない
return 0;
}
このコードでは、publicMethod
のみがBase
クラスのポインタを通じて呼び出すことができます。protectedMethod
とprivateMethod
は、それぞれのアクセス指定子のため、直接アクセスできません。
アクセス指定子とvtableの相互作用を理解することで、クラスの設計とセキュリティを向上させ、柔軟で保守しやすいコードを作成することができます。適切なアクセス制御を行うことで、安全で効率的なオブジェクト指向プログラミングが可能となります。
高度な応用例
アクセス指定子と仮想関数を駆使した高度なプログラム例を通じて、これらの概念をより深く理解します。このセクションでは、複雑な継承構造や多重継承を利用して、アクセス制御と動的バインディングを活用したプログラムを紹介します。
実用例: 多重継承とアクセス制御
以下の例では、多重継承を用いて異なる基底クラスからメンバーを継承し、それぞれに異なるアクセス指定子と仮想関数を適用します。
#include <iostream>
class Animal {
public:
virtual void makeSound() {
std::cout << "Some generic animal sound" << std::endl;
}
};
class Mammal {
protected:
virtual void walk() {
std::cout << "Mammal walking" << std::endl;
}
};
class Bat : public Animal, protected Mammal {
public:
void makeSound() override {
std::cout << "Screech" << std::endl;
}
void walk() override {
std::cout << "Bat walking" << std::endl;
}
void fly() {
std::cout << "Bat flying" << std::endl;
}
};
void describeAnimal(Animal* animal) {
animal->makeSound();
}
void describeMammal(Mammal* mammal) {
// mammal->walk(); // エラー: protectedメンバにはアクセスできない
}
int main() {
Bat bat;
Animal* animal = &bat;
Mammal* mammal = &bat;
describeAnimal(animal); // Screech
// describeMammal(mammal); // エラー
bat.walk(); // Bat walking
bat.fly(); // Bat flying
return 0;
}
コード解説
- 基底クラス
Animal
:
makeSound
という仮想関数を定義し、一般的な動物の鳴き声を出力します。
- 基底クラス
Mammal
:
walk
というprotectedの仮想関数を定義し、哺乳類の歩行動作を出力します。
- 派生クラス
Bat
:
Animal
とMammal
を多重継承し、両方の仮想関数をオーバーライドします。makeSound
はpublicのままで、walk
はprotectedのままオーバーライドされます。- 新しいメソッド
fly
を追加して、コウモリの飛行動作を出力します。
アクセス指定子と多重継承の相互作用
Animal
クラスの仮想関数:makeSound
はpublicなので、describeAnimal
関数内でアクセス可能です。Mammal
クラスの仮想関数:walk
はprotectedなので、describeMammal
関数内では直接アクセスできません。- ただし、
Bat
クラス内ではアクセス可能であり、walk
メソッドをオーバーライドできます。
高度な応用例の利点
- 柔軟な設計: 多重継承を利用して、異なる基底クラスからメソッドを継承し、必要に応じてアクセス権を制御できます。
- 再利用性の向上: 基底クラスの機能を再利用しながら、新しい派生クラスに特有のメソッドを追加できます。
- 動的バインディングの活用: 仮想関数とvtableを利用することで、実行時に適切なメソッドが呼び出されるようになります。
このように、アクセス指定子と仮想関数を組み合わせることで、C++のオブジェクト指向プログラミングにおいて高度で柔軟な設計が可能となります。多重継承やアクセス制御を理解し、適切に活用することで、より効率的で保守性の高いコードを実現しましょう。
演習問題
以下の演習問題を通じて、C++のアクセス指定子と仮想関数およびvtableに関する理解を深めましょう。各問題に対して、自分でコードを書いて動作を確認してみてください。
問題1: アクセス指定子の適用
クラスPerson
を作成し、次のメンバーを持つようにしてください:
- 名前(
name
):private - 年齢(
age
):protected - 公開メソッド
setName
とgetName
:public - 公開メソッド
setAge
とgetAge
:public
さらに、クラスEmployee
をPerson
から継承し、setName
およびgetName
メソッドを使って名前を設定し、出力するプログラムを作成してください。
class Person {
private:
std::string name;
protected:
int age;
public:
void setName(std::string n) {
name = n;
}
std::string getName() {
return name;
}
void setAge(int a) {
age = a;
}
int getAge() {
return age;
}
};
class Employee : public Person {
public:
void displayInfo() {
std::cout << "Name: " << getName() << std::endl;
std::cout << "Age: " << getAge() << std::endl;
}
};
int main() {
Employee emp;
emp.setName("Alice");
emp.setAge(30);
emp.displayInfo();
return 0;
}
問題2: 仮想関数のオーバーライド
以下の基底クラスShape
を定義し、仮想関数draw
を宣言してください。その後、派生クラスCircle
とSquare
を作成し、それぞれのクラスでdraw
メソッドをオーバーライドしてください。最後に、Shape
クラスのポインタを使って、Circle
およびSquare
のdraw
メソッドを呼び出すプログラムを作成してください。
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a shape" << std::endl;
}
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing a circle" << std::endl;
}
};
class Square : public Shape {
public:
void draw() override {
std::cout << "Drawing a square" << std::endl;
}
};
int main() {
Shape* shape1 = new Circle();
Shape* shape2 = new Square();
shape1->draw(); // Drawing a circle
shape2->draw(); // Drawing a square
delete shape1;
delete shape2;
return 0;
}
問題3: vtableの理解
次のコードを実行し、Animal
クラスとDog
クラスのmakeSound
メソッドがどのように呼び出されるかを確認してください。特に、vtableを通じた動的バインディングがどのように機能するかを理解してください。
class Animal {
public:
virtual void makeSound() {
std::cout << "Some generic animal sound" << std::endl;
}
};
class Dog : public Animal {
public:
void makeSound() override {
std::cout << "Woof! Woof!" << std::endl;
}
};
void describeAnimalSound(Animal* animal) {
animal->makeSound();
}
int main() {
Dog dog;
Animal* animal = &dog;
describeAnimalSound(animal); // Woof! Woof!
return 0;
}
これらの演習問題を通じて、C++のアクセス指定子、仮想関数、vtableに関する知識を実践的に確認し、理解を深めてください。各問題に対して自分でコードを書き、動作を確認することが学習のポイントです。
まとめ
本記事では、C++のアクセス指定子(public、private、protected)と仮想関数および仮想関数テーブル(vtable)について詳しく解説しました。アクセス指定子は、クラスのメンバーへのアクセス制御を行うための重要な要素であり、データのカプセル化と安全性の向上に寄与します。仮想関数とvtableは、オブジェクト指向プログラミングにおいて動的バインディングとポリモーフィズムを実現するための基盤となります。
各アクセス指定子の使い方と特徴、仮想関数の定義方法とその実用例、そしてvtableの仕組みと動作原理を理解することで、より柔軟で保守性の高いプログラムを設計することが可能になります。さらに、演習問題を通じて、実際のコードでこれらの概念を試し、理解を深めることができました。
これらの知識を活用し、C++プログラミングのスキルを一層向上させましょう。適切なアクセス制御と動的バインディングを駆使して、安全で拡張性の高いコードを書くことができるようになることを目指してください。
コメント