名前空間とは?
プログラムが大きくなると、関数名や変数名が重複する可能性が高まるのでそれを回避するために使われます。
構文
1 2 3 |
namespace 名前空間名{ 関数や、変数等 } |
全ての関数や変数が「名前空間」に属しているのか?
全ての関数や変数が「名前空間」に属しているわけではありません。
属していない関数やグローバル変数は、グローバル名前空間にて管理をされます。
名前空間を使うには?
スコープ演算子「::」を使い、下記のように指定をします。
通常の名前空間
1 |
名前空間名::識別子 |
グローバル名前空間の場合
名前空間名を指定しません。
1 |
::識別子 |
名前空間表記を省略するには?
using指令を使う。
一つの手法として、using指令を使います。
構文
名前空間までしか指定しない場合
1 |
using 名前空間; |
この場合は、範囲は広まり、使える変数や関数の数が増えますが、衝突の可能性が高まるのでできるだけ使わない方がよいでしょう。
例えば、「using namaspace std;」を使うとほとんどのC++標準ライブラリを使うことができますが、衝突する可能性のある範囲が広がってしまうので、面倒ですが、また下で解説する識別子まで指定する形としましょう。
識別子まで指定する場合
1 |
using 名前空間::識別子; |
この場合は、参照できる範囲は狭まりますが、次の問題点で挙げさせて頂く、後で修正した場合の影響を抑えることができます。
(これでも確実に回避はできないです。特定の名前空間ではなく、グローバル名前空間で同じ関数や変数名が使われてしまった場合は、名前の衝突が発生する可能性があるためです。)
省略できない場合もある。
複数の名前空間で関数や変数の名前が衝突していた場合は、仮にusing指令を使ったとしても名前空間の指定を省略できません。
using指令には問題点もある。
後で、関数や変数名を追加した際に名前が衝突してしまう可能性もあります。
その場合は、呼び出し先でusingを使っている個所を修正しなければならない可能性も発生します。
なので、できるだけusing指令を使わない方がよいという方もいらっしゃいます。
using指令を使わずに、名前空間を部分的に省略する。
例
下記のようにnamespaceに別名を付けることができます。
1 |
namespace TEST = TEST1::TEST2::TEST3; |
完全に名前空間指定を省略するわけではないですが、深い階層の名前空間が使われてしまっていた場合等にはプログラムの記述をすっきりさせることができ有効な手法となります。
変数
グローバル変数
関数、クラス、名前空間の外で宣言される変数のことです。
変数のスコープは、グローバル変数が宣言された位置から、ファイルの終わりまでになります。
グローバル変数をファイルをまたいで共有したい場合
グローバル変数は、ファイル内でのみしか使えません。
別ソースの関数等でも使いたい場合は、externキーワードを使います。
構文
1 |
extern 型名 変数名; |
ここで指定する変数名というのは、別ファイルで定義されている変数名になります。
なお、externで定義した変数名と同じ名前のグローバル変数が複数ファイルにあるとコンパイルできないので注意しましょう。
グローバル変数にstaticを付けた場合
下記のように、グローバル変数にstaticを付けた場合は、外部ファイルから参照することを禁止したグローバル変数になります。
1 |
static int a =3; |
ローカル変数
関数の中で定義される変数のことであり、変数のスコープはその関数の中でのみ有効です。
1 2 3 4 5 |
int add(){ int a = 0;//この関数の中でのみ有効で、呼び出しの都度初期化される。 ++a; return a; } |
静的変数
キーワード「static」を付けた変数のことです。
最初に呼び出されたときに一度だけ初期化をされ、その関数のすべての呼び出しで共有化されます。
なので、最初は初期化をされますが、次に呼び出されたときは初期化処理は行われません。
例
1 2 3 4 5 |
int add(){ static int a = 0;//最初だけ初期化される。 ++a; return a; } |
型推論
代入される値によって自動的に型を決めてくれる機能です。
構文
型には、「auto」というキーワードを使います。
1 |
auto 変数名 = 値; |
例えば、値に10を代入すればint型になりますし、3.2を代入すればdouble型になります。
どの型が選ばれているかは、Visual Studioをお使いであればマウスでポイントすればわかります。
C++におけるクラスの特徴
C#やJavaとは異なり、C++ではクラスを作ることができますが、クラスを作らなくてもプログラムの作成は可能です。
クラスを作る。
構文
1 2 3 4 5 6 7 |
class クラス名{ private: //非公開関数と変数 データメンバ名 変数名; public: //公開関数と変数 } |
Privateを省略した場合は、指定がないメンバに関してはprivateになります。
また、class自体は「classキーワード」だけではなく、「structキーワード」を使うこともできます。その場合は、指定なしのメンバはpublicになるので、その違いに注意しましょう。
クラスを使う。
構文
自動メモリにクラスを定義
1 2 |
クラス名 インスタンス名; インスタンス名.メンバ名; |
フリーストアにクラスを定義
1 2 |
インスタンス名 -> メンバー変数 インスタンス名 -> メンバー関数() |
1 2 |
クラス* インスタンス名 = new クラス名(); インスタンス名 -> 関数(); |
C++のクラスで、Java等のクラスと異なる点としては、「クラス」にもポインタを使うことができる点でしょう。
メンバ変数の定義
静的メンバ変数を定義する。
メンバ変数にstaticキーワードをつけると、全てのインスタンス共通のメンバ変数とすることができます。
下記のように、クラス内で実体を宣言しないとコンパイルエラーになってしまうので注意です。
1 |
型 クラス名::変数名; |
メンバ関数を定義する。
プログラムが大きくなる場合は、クラスの定義をヘッダファイル(.h)に記述し、メンバ関数をソースファイル(.cpp)に記述するのが一般的になります。少し、JavaやC#のメソッド定義とは異なりますよね。
これは、ヘッダファイル「クラスの定義(仕様)」と、ソースファイル「実装」を分離して、コードを単純化する目的があるためです。
構文
クラス定義の中で、メンバ関数の宣言をまず行います。
1 2 3 |
class クラス名{ 戻り値 メンバ関数(パラメータリスト); } |
次に、メンバ関数を定義します。具体的な処理内容はクラスの外で定義するので注意です。
また、メンバ関数が属するクラスを明示します。
1 2 3 |
戻り値の型 クラス名::メンバ関数名(パラメータ){ 処理内容 } |
クラステンプレートを使う。
クラスもテンプレート化することができます。
構文
1 |
template <typename T> |
クラス内で「T」という型を指定することで、クラス生成時に色々な型(int、double等)を定義することができます。
クラスの初期化
コンストラクタを使う。
クラスからオブジェクトを構築する場合に「コンストラクタ」というメンバ関数が呼ばれます。
クラス内で下記の構文を使います。
1 2 3 |
クラス名(パラメータリスト){ 処理内容 } |
デフォルトコンストラクタ
引数のないコンストラクタのことを「デフォルトコンストラクタ」と呼びます。
何も記述しなければ、暗黙的に定義されますが、一つでもコンストラクタを定義してしまうと暗黙定義のコンストラクタは定義されないので注意です。
初期化専用の構文を使う。
C++のクラスでは、「コントラクタ」以外にも初期化専用の構文が用意されています。
場合によっては、それを使った方が効率が良くなる場合があります。
1 |
クラス名(パラメータリスト) : フィールド名(値),… |
クラスの解体(デストラクタ)
デフォルトコンストラクタと同様に、クラスを解体するときに暗黙的に定義されます。
ただ、暗黙デストラクタは何もしないので、何かさせたい場合は下記のように明示します。
1 2 3 |
~クラス名() { 処理内容 } |
なお、クラスの解体はメインプログラムの方で、delete文を使うと解体されます。
デストラクタの重要な役割
デストラクタの重要な役割としては、データメンバがフリーストアに配置をされる場合です。
データメンバが持つポインタをdelete ポインタとして、解体してあげる必要があります。
そうしないとメモリリークの発生率が高まってしまいます。
ポインタをクラスメンバにする意義
前提
例えば、下記のようなクラスがあるとします。
1 2 3 |
class Test{ int a; } |
メインプログラムの中で、下記のようにnewでフリーストアに対してオブジェクトを格納したとしたら、解放する前に途中で例外が発生したりするとメモリリークの危険性が増してしまいます。
1 2 3 4 5 |
//クラスをnewする。 Test* test = new Test; ★ここで例外発生 //作ったクラスを解放する。 delete test; |
そこで、下記のようにリソースを管理するための別のオブジェクトを作成して、コンストラクタとデストラクタでのみオブジェクトの作成と解放を行わせます。
1 2 3 4 5 6 7 8 9 |
class Test{ int a; } class WrapTest{ Test* test; WrapTest(): test(new test){} ~WrapTest() {delete test;} } |
このような手法のことを資源獲得時初期化と呼んでいて、よく使われています。
標準関数
C++は、関数の集合体になり、プログラムで実行される操作のほとんどを関数の中に記述することになります。
使い方
基本的には、「#include <ヘッダファイル名>」でライブラリをインクルードして、引数と戻り値の型さえ意識すれば普通に使うことができます。
下記のようなサイトで確認することができます。
cppjp
https://cpprefjp.github.io/
cplusplus
http://www.cplusplus.com/
自作関数
もちろん、自分で関数を作ることも可能です。
構文
1 2 3 |
戻り値の型 関数名(パラメータ名){ 処理内容; } |
外部ファイルの関数をするには?
関数プロトタイプ宣言をすればそれだけで外部ファイルの関数を使えます。
例
参照元
1 2 3 4 5 6 7 |
#include <iostream> using namespace std; void Func() { cout << "参照されます。"; } |
参照先
1 2 3 4 5 6 7 8 9 10 11 |
#include <iostream> using namespace std; //プロトタイプ宣言 void Func(); int main() { //外部ファイルの関数を使える。 Func(); } |
変数の場合は、外部ファイルの変数を使う場合は、externをつける必要がありましたが、関数の場合はプロトタイプ宣言をすれば使えるのです。
外部ファイルから関数を参照させたくない場合
外部ファイルでプロトタイプ宣言をすれば、外部から関数を参照できます。
それをさせたくない場合は、staticキーワードを付けます。
1 2 3 |
static 戻り値 関数名(){ 処理内容; } |
仮想関数とは?
C++において基底クラスの関数をオーバーライドする際に、必要な条件の一つです。
オーバーライドさせたい基底クラスの関数は、「仮想関数」にする必要があるのです。
構文
仮想関数の定義は簡単です。
基底クラスの関数の一番先頭に「Virtual」というキーワードをつけるだけです。
1 2 3 |
class 基底クラス名{ virtual void 関数名(){}; } |
関数テンプレートとは?
例えば、戻り値や、引数の型だけ違い、処理内容が全く同じという関数がある場合があると思います。
そうした場合に、型を定めずに、記述するというC++の「関数テンプレート」という機能があります。
構文
1 2 3 4 5 |
template <typename T> T 関数名(T num){ numを使った処理内容 } |
テンプレート仮引数
色々使われますが、最もよく使われるのが「typename」というテンプレート仮引数になります。
入出力演算子
C言語でいうところの「print()」(出力)や、「scanf()」(入力)にあたる機能のことです。
出力演算子
構文例
1 |
count << 出力したい値 |
coutは、既定義のストリームになります。
出力文字列の最後で改行したい場合は、endlというキーワードを使います。
1 |
cout << "出力文字列" << endl; |
入力演算子
1 |
cin >> 入力したい値 |
サンプルプログラム
1 2 3 4 5 6 7 8 9 10 |
#include <iostream> using namespace std; int main() { int i; cout << "値を入力してください:"; cin >> i; cout << i; } |
この記事へのコメントはありません。