【C++言語入門】 第7回 ファイル毎にクラスを
クラスを別ファイルに
Circle
クラスを別ファイルに移してみましょう
- まず、
Circle
クラス全体をコメントアウト - ソリューションエクスプローラーで Project2 を右クリック
- メニューから 追加... → クラス... を選択
- クラスの追加 ダイアログボックスの クラス名 に"Circle"、 .hファイル を"circle.h"に、 .cppファイル を"circle.cpp"に変更
- 基底クラス は空欄、 インライン がチェックされていないことを確認してOKをクリック
- 新規に作成された"circle.h"にインクルードガード(CIRCLE_H)を追加
- "circle.h"に
Circle
クラス全体を移動しコメントアウトを解除 - "circle.h"に定数を移動しヘッダー"iostream"を追加
- "hello_world.cpp"に"circle.h"ヘッダーファイルをインクルード
Circle
クラスは必要ないので、コメントアウトしておきますわ
#include <iostream>
//const double kPI = 3.14159265358979323846;
//const int kMessageSize = 50;
//
///// @brief 円
//class Circle {
// double diameter_; // 直径
// double border_width_; // 境界線の幅
// char* pmessage_;
//
// public:
// Circle(double diameter, double border_width)
// : diameter_(diameter), border_width_(border_width), pmessage_(nullptr) {
// pmessage_ = new char[kMessageSize];
// }
// ~Circle() {
// std::cout << "デストラクタが呼ばれました" << std::endl;
// delete[] pmessage_;
// pmessage_ = nullptr;
// }
//
// double Diameter() { return diameter_; }
// void Diameter(double diameter) { diameter_ = diameter; }
// double BorderWidth() { return border_width_; }
// void BorderWidth(double border_width) { border_width_ = border_width; }
//
// double Area() {
// double radius = Diameter() / 2.0;
// double a = radius * radius * kPI;
// return a;
// }
//
// const char* Message() {
// double area = Area();
// sprintf_s(pmessage_, kMessageSize, "円の面積は%fです。", area);
// return pmessage_;
// }
//};
int main(int argc, char* argv[]) {
Circle* pc = new Circle(10.0, 1.0);
std::cout << "円の直径は" << pc->Diameter() << "cmです。" << std::endl;
std::cout << pc->Message() << std::endl;
delete pc;
pc = nullptr;
return 0;
}
Circle
クラスが残っていると新たにCircle
クラスを作成できないのですわ
#pragma once
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
const double kPI = 3.14159265358979323846;
const int kMessageSize = 50;
/// @brief 円
class Circle {
double diameter_; // 直径
double border_width_; // 境界線の幅
char* pmessage_;
public:
Circle(double diameter, double border_width)
: diameter_(diameter), border_width_(border_width), pmessage_(nullptr) {
pmessage_ = new char[kMessageSize];
}
~Circle() {
std::cout << "デストラクタが呼ばれました" << std::endl;
delete[] pmessage_;
pmessage_ = nullptr;
}
double Diameter() { return diameter_; }
void Diameter(double diameter) { diameter_ = diameter; }
double BorderWidth() { return border_width_; }
void BorderWidth(double border_width) { border_width_ = border_width; }
double Area() {
double radius = Diameter() / 2.0;
double a = radius * radius * kPI;
return a;
}
const char* Message() {
double area = Area();
sprintf_s(pmessage_, kMessageSize, "円の面積は%fです。", area);
return pmessage_;
}
};
#endif // CIRCLE_H
#include <iostream>
#include "circle.h"
int main(int argc, char* argv[]) {
Circle* pc = new Circle(10.0, 1.0);
std::cout << "円の直径は" << pc->Diameter() << "cmです。" << std::endl;
std::cout << pc->Message() << std::endl;
delete pc;
pc = nullptr;
return 0;
}
メソッドを別ファイルに
Area
メソッドやMessage
メソッドの定義を行うのですわ
Circle
クラスのコンストラクタやデストラクタ、Area
メソッドやMessage
メソッドの宣言をおこなうのか
#pragma once
#ifndef CIRCLE_H
#define CIRCLE_H
#include <iostream>
const double kPI = 3.14159265358979323846;
const int kMessageSize = 50;
/// @brief 円
class Circle {
double diameter_; // 直径
double border_width_; // 境界線の幅
char* pmessage_;
public:
Circle(double diameter, double border_width);
~Circle();
double Diameter() { return diameter_; }
void Diameter(double diameter) { diameter_ = diameter; }
double BorderWidth() { return border_width_; }
void BorderWidth(double border_width) { border_width_ = border_width; }
double Area();
const char* Message();
};
#endif // CIRCLE_H
#include "circle.h"
Circle::Circle(double diameter, double border_width)
: diameter_(diameter), border_width_(border_width), pmessage_(nullptr) {
pmessage_ = new char[kMessageSize];
}
Circle::~Circle() {
std::cout << "デストラクタが呼ばれました" << std::endl;
delete[] pmessage_;
pmessage_ = nullptr;
}
double Circle::Area() {
double radius = Diameter() / 2.0;
double a = radius * radius * kPI;
return a;
}
const char* Circle::Message() {
double area = Area();
sprintf_s(pmessage_, kMessageSize, "円の面積は%fです。", area);
return pmessage_;
}
メソッドの定義の方法は?
型 クラス名::メソッド名(引数...) {処理 }
のようになりますわ
クラス内のメソッドの宣言の方法は?
メソッドの定義を別ファイルにするメリットは?
メソッドの定義をクラスのヘッダーファイルではなく、ソースファイルで行うのには何かメリットがあるのでしょうか
有名どころのプログラム言語、例えば Java や Python 、 C# などは、基本的に定義と宣言を分けません
ヘッダーファイルに宣言、ソースファイルに定義と分離するのはC言語やC++言語の特徴のひとつでしょう
ヘッダーファイルとソースファイルに宣言と定義を分ける主なメリットは以下の通りです
- プログラム生成時間の短縮
メソッドの定義を修正した場合、ヘッダーファイルが宣言のみで変更が無ければ、ヘッダーファイルをインクルードしたソースファイルの再コンパイルは必要ありません。
もしヘッダーファイルに定義も含んでいた場合には、全てのソースファイルを再コンパイルする必要があるため、大規模なプログラムでは生成時間が問題となってきます
- モジュールの管理
ライブラリを作成、提供する際、ヘッダーファイルにメソッドの定義が書かれていると、実装内容が公開されることになるため、メソッドを修正し難くなります
ヘッダーファイルに宣言のみを記述していれば、メソッドの定義の修正はライブラリの利用者に及ぼす影響を最小限に抑えられます
なお、ヘッダーファイルの宣言とソースファイルの定義の整合性や宣言と定義の両方に必要な記述の分の作業量が増えるなどのデメリットも存在します
最近の高速なPCで大規模ではないプログラムを作る限りでは、あまりメリットを感じないかもしれません
インライン関数は特殊ですよ
inline
キーワードを付加した関数を インライン関数 と呼びますわ
#include <iostream>
void print() {
std::cout << "これはテストです。" << std::endl;
return;
}
int main(int argc, char* argv[]) {
print();
return 0;
}
print
関数がコールされた際には、print
関数が呼ばれるプログラムですわね
inline
キーワードが付加されると状況が変わりますわ
#include <iostream>
inline void print() {
std::cout << "これはテストです。" << std::endl;
return;
}
int main(int argc, char* argv[]) {
print();
return 0;
}
int main(int argc, char* argv[]) {
std::cout << "これはテストです。" << std::endl;
return 0;
}
print();
の部分がprint
関数の処理内容で置き換わって、print
関数がなくなっているのだ
inline
キーワードを付加された状態とみなされますわ
Discussion