最も重要なOOP機能:
- 概要
- カプセル化とデータの隠蔽
- 多形性
- 継承
- コードの再利用性
これらの機能を実装して組み合わせるために、C ++によって行われた最も重要な改善は、クラスを提供することです。これまでの記事のほとんどはプロセス指向プログラミングについて話していましたが、今度はオブジェクト指向プログラミングを正式に紹介します。
1.抽象化とクラス
1.1 C ++のクラス
キーワードclassを使用してクラスの設計を示します。ここでは、typenameを使用できません。クラス仕様は2つの部分で構成されています。
クラス宣言:データ部分をデータメンバーの形式で記述し、パブリックインターフェイスをメンバー関数(メソッド)の形式で
記述します。クラスメソッド定義:クラスメンバー関数の実装方法を記述します。
簡単に言えば、クラス宣言はクラスの青写真を提供し、メソッド定義は詳細を提供します。クラスでは、メンバー関数をクラスで定義することも、プロトタイプで表すこともできます。
(1)アクセス制御
キーワードprivateおよびpublicは、クラスメンバーへのアクセス制御を表します。クラスオブジェクトはパブリックパーツに直接アクセスできますが、パブリックメンバー関数(またはフレンド関数)を介してのみオブジェクトのプライベートメンバーにアクセスできます。C ++は、クラス継承で導入されるprotectedキーワードも提供します。
データを隠すことは、データへの直接アクセスを妨げるだけでなく、開発者(クラスユーザー)がデータがどのように表現されているかを知ることから解放されます。
(2)メンバーへのアクセスを制御する:パブリックまたはプライベート
データを非表示にすることはOOPの主な目標の1つであるため、データ項目は通常プライベートメンバー部分に配置され、クラスインターフェイスを構成するメンバー関数はパブリック部分に配置されます。もちろん、メンバー関数をプライベート部分に配置することもできるため、パブリックメソッドを介してのみ呼び出すことができ、プログラムから直接プライベートメンバー関数を呼び出すことはできません。
これはクラスのデフォルトのアクセス制御メソッドであるため、クラス宣言のprivateは省略できます。
class World
{
float mass;
public:
void tellall(void);
}
データ隠蔽の概念を強調するために、ここでは明示的にプライベートを使用します。
(3)クラスと構造
クラスの説明は、構造体の宣言によく似ています(すべてにメンバー関数、パブリックタグとプライベートタグがあります)。実際、C ++は構造を拡張して、クラスと同じ特性を持つようにします。構造体のデフォルトのアクセスタイプはpublicであり、クラスはprivateです。
C ++プログラマーは通常、クラスを使用してクラス記述を実装し、構造を純粋なデータオブジェクトに制限します。
1.2クラスメンバー関数を実装する
(1)メンバー関数の定義
メンバー関数は通常の関数と非常に似ていますが、2つの特別な特性があります。
- クラスメンバー関数を定義するときは、解析演算子(::)を使用して、関数が属するクラスを識別します。
- クラスメソッドは、クラスのプライベートコンポーネントにアクセスできます。
クラス定義:
void Stock::update(double price)
{
...}
(2)インライン方式
メンバー関数の定義クラス宣言の関数は、自動的にインライン関数になります。クラス宣言では、多くの場合、インライン関数として小さなメンバー関数を使用します。
必要に応じて、クラス宣言の外部でメンバー関数を定義し、それらをインライン関数にすることができます。クラス実装セクションで関数を定義するときは、インライン修飾子を使用するだけです。
inline void Stock::set_tot()
{
...}
インライン関数の特別なルールでは、それらを使用するすべてのファイルで定義する必要があるため、通常、インライン定義を定義クラスのヘッダーファイルに配置します。
2.クラスコンストラクタとデストラクタ
C ++の目標の1つは、標準型を使用するのと同じようにクラスオブジェクトを使用することです。int型などのクラスオブジェクトを初期化するには、プライベートメンバーにアクセスする必要があります。したがって、適切なメンバー関数を設計する必要があります。オブジェクトの初期化を正常に変換します。このため、C ++は、新しいオブジェクトを構築するために特に使用される特別なメンバー関数クラスコンストラクターを提供します。
2.1コンストラクターを宣言して定義する
コンストラクターのプロトタイプは次のとおりです。次のプロトタイプはデフォルトのパラメーターを使用します。
Stock(const string& co, long n = 0, double pr = 0.0);
これは次のように定義されています。
Stock::Stock(const string& co, long n, double pr)
{
company = co;//赋值给私有数据成员
...
}
プライベートデータメンバーを他の変数と区別するために、company_などのアンダースコアが追加されることがよくあります。
2.2コンストラクターの使用
- 呼び出しコンストラクターを表示する
Stock food = Stock("world cabbage", 250, 1.25);
- 隠者はコンストラクターを呼び出します
Stock garment("Furry Mason", 50, 2.5);
クラスオブジェクトを作成するたびに(newを使用して動的にメモリを割り当てる場合でも)、C ++はクラスコンストラクタを使用します。
Stock * pstock = new Stock("Electroshock", 18, 19.0);
上で作成されたオブジェクトには名前がありませんが、作成されたオブジェクトのアドレスがpstockに割り当てられます。
- C ++リストの初期化
Stock hot_tip = {
"Derivatives", 100, 45};
Stock jock {
"Sport Age Storage"};
Stock temp {
};
2.3デフォルトコンストラクタ
初期値が指定されていない場合は、デフォルトのコンストラクターが呼び出されます。例えば:
Stock fluffy_the_cat;//使用默认构造函数
クラスにコンストラクターが提供されていない場合、C ++は自動的にデフォルトのコンストラクターを提供し、何の作業も行いません。
Stock::Stock( ) {
};
コンストラクターが定義されていない場合にのみ、コンパイラーがデフォルトのコンストラクターを提供することに注意してください。クラスがコンストラクターを定義する場合、ユーザーはそのデフォルトのコンストラクターを提供する必要があります。デフォルト以外のコンストラクターが提供されているが、デフォルトのコンストラクターが提供されていない場合、次の宣言は誤りになります。
Stock stock1;//没有默认构造函数,报错!!!
次の定義の違いに注意してください。
Stock first("Concrete");//隐式构造函数调用,非默认构造函数调用
Stock second();//定义一个函数,它的返回值为Stock类型
Stock third;//隐式地调用默认构造函数。
2.4デストラクタ
オブジェクトの有効期限が切れると、プログラムは自動的に特別なメンバー関数-destructorを呼び出します。デストラクタはクリーンアップ作業を完了しますが、これは実際には非常に便利です。たとえば、newによって割り当てられたメモリをクリーンアップするには、デストラクタの定義でクラス名の前に〜を追加するだけでよいため、Stockのデストラクタは〜Stock()です。 。
デストラクタは重要な作業を行わないため、何もしない関数として記述できます。
Stock::~Stock()
{
...}
- 静的ストレージクラスオブジェクトを作成すると、そのデストラクタはプログラムの最後に自動的に呼び出されます。
- 自動ストレージクラスオブジェクトを作成すると、プログラムがコードブロックの実行を終了すると、そのデストラクタが自動的に呼び出されます。
- オブジェクトがnewによって作成された場合、そのオブジェクトは空きストレージ領域に存在し、deleteを使用してメモリを解放すると、そのデストラクタが自動的に呼び出されます。
デストラクタが必要です。プログラマがデストラクタを提供しない場合、コンパイラはデフォルトのデストラクタを秘密裏に宣言します。
2.5constメンバー関数
constオブジェクトを定義すると、それ自体の関数を呼び出すことはできません。例えば:
const Stock land = Stock("kludgehorn");
land.show();//不被允许,因为不能确保调用的对象不被修改!!!
解決策は、メンバー関数の宣言とメンバー関数の定義の後にconstを追加して、関数が呼び出し元のオブジェクトを変更しない(土地を変更しない)ようにすることです。
void show() const;//成员函数原型
void Stock::show() const//成员函数定义
{
...
}
このように定義されたメンバー関数は、constメンバー関数と呼ばれます。
3.このポインタ
メソッドが2つのオブジェクトに対して設計されている場合、C ++のthisポインターを使用する必要がある場合があります。たとえば、2つのオブジェクトの値を比較する場合は、どちらを使用しても、次のように呼び出すことができます。
top = stock1.topval(stock2);//显示调用stock2,隐式调用stock1
top = stock2.topval(stock1);//显示调用stock1,隐式调用stock2
特定のコード定義フラグメント:
const Stock& Stock::topval(const Stock& s) const
{
if(s.total_val > total_val)
return s;//返回被调用的对象
else
return *this;//返回自己的对象本身,this是本身的地址
}
上記のコードスニペットの次の点に注意してください。
- sは、オブジェクトが明示的にアクセスされ、topvalを呼び出すオブジェクトが暗黙的にアクセスされることを示します。
- 括弧内のconstは、明示的にアクセスされるオブジェクトが変更されないことを意味し、括弧の後のconstは、暗黙的にアクセスされるオブジェクトが変更されないことを意味します。
- これは暗黙的にアクセスされるオブジェクトのアドレスであり、*これはオブジェクトを表します。
4.オブジェクト配列
オブジェクトの配列に複数のオブジェクトを作成できます。以下は4つのオブジェクトを作成し、それぞれがデフォルトのコンストラクターを呼び出します。
Stock mystuff[4];//创建4个对象
データメンバーとメンバー関数にアクセスするために使用できます。
mystuff[0].update();
mystuff[0].show();
デフォルトのコンストラクターを使用したくない場合は、コンストラクターのタイプを自分で選択できます。
const int STKS = 4;
Stock stocks[STKS] = {
Stock("Nano", 12.5, 20),
Stock();
Stock("Mono", 130, 3.25),
};
stocks [0]とstocks [2]は同じコンストラクターを使用し、stocks [1]はデフォルトのコンストラクターを使用し、stocks [3]は表示の初期化を実行せず、デフォルトのコンストラクターも呼び出します。
5.クラススコープ
クラスで定義された名前のスコープ(クラスデータメンバーの名前やクラスメンバー関数の名前など)はクラス全体であり、スコープはクラス全体の名前がクラス内でのみ認識されることです。 、ただしクラス外ではありません。
クラス外のメンバーを使用する場合は、コンテキストに応じて、直接メンバー演算子(。)、間接メンバー演算子(->)、またはスコープ解決演算子(::)を使用する必要があります。
5.1スコープがクラスである定数
クラス宣言のリテラル値がすべてのオブジェクトで同じである場合、クラスを使用してそれにアクセスできます。ただし、クラスの定義時にスペースが割り当てられないため、次の操作は誤りです。
class Bakery
{
private:
const int Months = 12;//不可以
double consts[Months];
上記の操作を実現するには、次の2つの方法があります。
(1)列挙
class Bakery
{
private:
enum{
Months = 12};
double consts[Months];
この方法で列挙を宣言しても、クラスデータメンバーは作成されません。つまり、すべてのオブジェクトに列挙が含まれているわけではありません。さらに、Monthsは単なる記号名であり、クラス全体のコードでMonthsに遭遇すると、コンパイラーはそれを30に置き換えます。
(2)静的
class Bakery
{
private:
static const int Months = 12;
double consts[Months];
これにより、Monthsという定数が作成され、オブジェクトではなく他の静的変数とともに保存されます。したがって、Bakeryオブジェクトによって共有されるMonths定数は1つだけです。C ++ 98では、この手法は、値と整数または列挙を使用して静的定数を宣言するためにのみ使用できますが、二重定数を格納することはできません。C ++ 11は、この制限を排除します。
クラスの初期化は静的データのみであることに注意してください。メンバーは整数型または列挙型constです。他のタイプは、クラスを定義するcppファイルで初期化する必要があります。
5.2スコープ内の列挙(C ++)
従来の列挙にはいくつかの問題があります。たとえば、次の列挙は競合します。
enum egg {
Small, Medium, Large, Jumbo };
enum t_shirt {
Small, Medium, Large, Xlarge};
上記のコードは、eggとt_shirtの列挙が同じであるためコンパイルできず、競合します。この問題を解決するために、C ++ 11はスコープがクラスである新しい列挙を提供します。
enum class egg {
Small, Medium, Large, Jumbo };
enum class t_shirt {
Small, Medium, Large, Xlarge};
クラスの代わりにstructを使用することもできます。使用するメソッドに関係なく、列挙名を使用して列挙を制限する必要があります。
egg choice = egg::Large;
t_shirt Floyd = t_shirt::Large;
C ++ 11は、暗黙的に整数に変換できないスコープ内列挙の型安全性も向上させます。
enum egg {
Small, Medium, Large, Jumbo };//普通类型
enum class t_shirt {
Small, Medium, Large, Xlarge};//类作用域
egg one = Medium;
t_shirt rolf = t_shirt::Large;
int king = one;//可以,普通类型转换
int ring = rolf;//不可以,不能进行作用域的转换
if(king < Jumbo)//可以
if(king < t_shirt::Medium)//不可以,不能隐士转换为int比较
ただし、明示的に変換することはできます。
int Frodo = int(t_shirt::Small);
デフォルトでは、列挙の基礎となる実装はintですが、C ++ 11では、特定の型の基礎となる実装を明示的に使用でき、基礎となる型は整数である必要があります。
enum class : short t_shirt {
Small, Medium, Large, Xlarge};//底层类型指定为short
6.抽象データ型
一般的な概念を表すためにクラスを使用する抽象データ型(抽象データ型、ADT)。クラスはADTを表すのに非常に適しており、パブリックメンバー関数インターフェイスはADTによって記述されたサービスを提供し、クラスのプライベート部分とクラスメソッドコードは実装を提供します。これらはクラスの顧客からは見えません。
概要カタログ
前:(7)メモリモデルと名前空間
次:(8)クラスの使用
記事の参照:「C ++ Primer PlusSixthEdition」