c++学習ノート(10.特別テーマ二経典問題解析)


このセクションの知識点:
1.mallocとfreeとnewとdeleteの違い:
a.mallocとfreeは
ライブラリ関数
バイト単位申請スタックメモリ
b.newとdeleteは
キーワード
タイプ単位申請スタックメモリ
c.mallocとfreeは単純にメモリの申請と解放を行い、初期化の責任を負わない.基本タイプnewキーワードについてはメモリの初期化を選択してもよいし、初期化しなくてもよい
   d.
クラスタイプnewとdeleteでは、コンストラクション関数とコンストラクション関数の呼び出しも担当します.
サンプルコード:
#include <iostream>
#include <malloc.h>

using namespace std;
class test
{
private:
	int a;
	int b;
public:
	int c;
	test(int a, int b)
	{
		this->a = a;
		this->b = b;
		c = 9;
		cout << "a is "<< a <<endl;
		cout << "b is "<< b <<endl;
	}
};
int  main()
{
	test *p = new test(1,2); //   new                    
	test *q = reinterpret_cast <test*> (malloc(sizeof(test))); //  malloc         
	cout << "q is " << q->c <<endl;
	cout << "c is " << p->c <<endl;	
	return 0;
} 

2.コンパイラがコンストラクション関数を呼び出す:a.一般クラスがオブジェクトを初期化する方法は3種類あり、
test t1(5);    test t2 = 5;     test t3  = test(5);  
現代のコンパイラでは彼ら3人は等価だが、コンパイラの内部から見ると違いがある.
   b.
test t 1(5)は最も単純で直接的であり、コンパイラにtestクラスの構造関数を直接呼び出すように強制した.
explicitは無効です).
test t 2=5には4つのステップがあります.第1、デフォルトでは、字面量5のタイプはintなので、5はtestオブジェクトの初期化に直接使用できません.第2ですが、コンパイラはデフォルトで構造関数を自動的に呼び出すことができます(
explicit有効)、第3に、コンパイラはtest(int)を呼び出して一時オブジェクトを生成しようと試み、第4に、最後にコピーコンストラクタtest(const test&obj)を呼び出してt 2を一時オブジェクトで初期化する(
explicit有効).
test t 3=test(5)は、まず、test(int)コンストラクタ(
explicitは無効です.最後に、コンパイラはデフォルトでコピーコンストラクション関数を自動的に呼び出します(
explicit有効)
c.c++コンパイラは、プログラムをコンパイルするためのさまざまな手段を試みます.
方法一:できるだけ重荷関数に一致させる
方法2:関数のデフォルトパラメータを最善を尽くす
方式3:構造関数を呼び出してタイプ変換を試みる
   d.
explicitキーワードを使用して、コンパイラによるコンストラクション関数の呼び出しを阻止します.コードは次のとおりです.
#include <iostream>
using namespace std;
class test
{
private:
	int a;
public:	
	//explicit 
	test(int c)
	{
		cout << "test()" <<endl;
	}
	//explicit 
	test(const test& p)
	{
		cout << "test(const test& p)" <<endl;
	}
	~test()
	{
		cout << "~test()" <<endl;
	}
};
int main()
{
	test a1(8);   //                         
	test a2 = 8; //                                 
	test a3 = test(8);  //                                  
	return 0;
}
   e.
もう一つの小さな問題は,test t 2=5のこの方式では,test(int a)のような構造関数を持つオブジェクトのみで初期化できることである.コンストラクション関数がtest(int a,int b)の場合、test t 2=(5,4)はコンパイルエラーになります!!!
3.単一モード:
a.一例モードは
クラスの静的メンバーの1つのとても良い応用、単例のモードは適用します
1つのクラスが1つのオブジェクトのみを生成できる場合
   b.
分析単例モード:このクラスは1つのオブジェクトしか生成できない以上、
このクラスの構造関数はprivate属性であるべきで、このクラスを作成するにはtest t 1(5)のような文を使用することはできません.
関数のみ使用できます(2種類あり、
1つは静的メンバー関数です
もう1つはグローバル関数を使用します.この中のアドレスを返す変数もグローバル変数でなければなりません.使用しないほうがいいです.これはクラスのカプセル化を破壊するからです.メンバー関数ができない理由は次のとおりです.
オブジェクトなしでメンバー関数を呼び出すことはできません.関数での使用
newキーワード、newというクラス、そして
newから出てきた新しいアドレスを返すにはstaticの静的メンバー変数が必要です.
この場合、この変数は静的メンバー変数を使用する必要があります.
クラスで使用するには(クラスの前またはクラスで定義する必要があります)、この変数のタイプ
やはりこのクラスのタイプやポインタのタイプ(クラスの後ろやクラスに定義すべき)、
他の関数に返すには、この変数を使用するのは静的タイプ(staticプロパティ)である必要があります.だから、上記の3つを満たす場合は、静的メンバー変数を使用します!!!
サンプルコード:
#include <iostream>
using namespace std;

class test
{
private:
	static test* tp;
	test()
	{
		
	}
public:	
	static test* creat()
	{
		if(NULL == tp)
		{
			cout << "hello" <<endl;
			tp = new test;
		}
		return tp;
	}

};
test* test::tp = NULL;
int main()
{
	test* only = test::creat();
	test* only1 = test::creat();
	return 0;
}

4.関数オブジェクトの実装:a.ステータス関数なし:関数の呼び出しは実パラメータ値のみに関連する
b.状態関数:関数の呼び出し結果は実パラメータ値だけでなく、以前の関数呼び出しにも関係し、記憶機能のある関数であり、static属性変数を利用する
サンプルコード:
#include <cstdlib>
#include <iostream>

using namespace std;

int fib1(int i)
{
    int a1 = 0;
    int a2 = 1;
    int ret = a2;
    
    while( i > 1)
    {
        ret = a2 + a1;
        a1 = a2;
        a2 = ret;
        i--;
    }
    
    return ret;
}

int fib2()
{
    static int a1 = 0;
    static int a2 = 1;
    
    int ret = a2;
    int t = a2;
    
    a2 = a2 + a1;
    a1 = t;
    
    return ret;
}

int main(int argc, char *argv[])
{
    for(int i=1; i<=10; i++)
    {
        cout<<fib1(i)<<endl;
    }
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib2()<<endl;
    }
    
    return 0;
}

注意:第一に、fib 1は無状態関数で実現され、数列の各項目を解く際に繰り返されるループであり、時間複雑度はO(n)である.
第二に、fib 2は状態関数として実現され、呼び出すたびに現在の項目の値を数列得ることができ、時間複雑度はO(1)であり、
でも最初からやり直せない
    c.
関数オブジェクトの実装:実際にはオブジェクトを利用してステータス関数をシミュレートし、static属性の変数の代わりにオブジェクトのメンバー変数を利用するが、同じように振り返ることはできない.コードは以下の通りである.
#include <cstdlib>
#include <iostream>

using namespace std;

int fib1(int i)
{
    int a1 = 0;
    int a2 = 1;
    int ret = a2;
    
    while( i > 1)
    {
        ret = a2 + a1;
        a1 = a2;
        a2 = ret;
        i--;
    }
    
    return ret;
}

int fib2()
{
    static int a1 = 0;
    static int a2 = 1;
    
    int ret = a2;
    int t = a2;
    
    a2 = a2 + a1;
    a1 = t;
    
    return ret;
}

class Fib
{
private:
    int a1;
    int a2;
public:
    Fib()
    {
        a1 = 0;
        a2 = 1;
    }
    
    int operator() ()
    {
        int ret = a2;
        int t = a2;
        
        a2 = a2 + a1;
        a1 = t;
        
        return ret;
    }
};

int main(int argc, char *argv[])
{
    cout<<"int fib1(int i)"<<endl;
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib1(i)<<endl;
    }
    
    cout<<endl;
    
    cout<<"int fib2()"<<endl;
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib2()<<endl;
    }
    
    cout<<endl;
    
    Fib fib;
    
    cout<<"Fib fib;"<<endl;
    
    for(int i=1; i<=10; i++)
    {
        cout<<fib()<<endl;
    }
    
    cout<<endl;
    
    return 0;
}