C++基礎知識を復習する-----「私の最初のC++」読書ノート2


抽象は一般的に属性抽象と行為抽象の2種類に分けられる.前者はオブジェクトが共有する属性または状態変数を探し、後者はこれらのオブジェクトが持つ共通の動作特徴を探す.新しいオブジェクトを解析するときは,属性と動作の2つの面から抽象と要約を行い,オブジェクトの共有を抽出してもよい.抽象があれば,インタフェース(虚関数)として抽出でき,クラスのメンバー属性とメンバー関数に直接変換できる.
親から継承され書き換えられた関数を子クラスで呼び出すにはどうすればいいですか?-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
#include "stdafx.h"
#include "iostream"
using namespace std;

namespace Zeng
{
	class CTest_A
	{
	public:
		CTest_A( int iValue )
		{
			this->m_iValue = iValue;
		}
		void print()
		{
			cout << "CTest_A's m_iValue current value is : " << this->m_iValue << endl;
		}
	private:
		int m_iValue;
	};

	class CTest_B : public CTest_A
	{
	public:
		CTest_B( int iValue ) : CTest_A( iValue )
		{
			this->m_iValue = iValue;
		}
		void print()
		{
			cout << "CTest_B's m_iValue current value is : " << this->m_iValue << endl;
		}
	private:
		int m_iValue;
	}; // virtual CTest_A    public CTest_A           
}

int _tmain(int argc, _TCHAR* argv[])
{
	Zeng::CTest_A* CB2 = new Zeng::CTest_B( 8 ); //                 
	CB2->print(); //          print  ,       CTest_A ,   CTest_B print   virtual   CTest_B 

	cout << "class CTest_A size is : " << sizeof( Zeng::CTest_A ) << endl;
	cout << "class CTest_B size is : " << sizeof( Zeng::CTest_B ) << endl;

	return 0;
}

thisポインタ:クラスなど
class Base
{
	public:
		void SetValue( int nVal )
		{
			m_nVal = nVal;
		}
	private:
		int m_nVal;
}

SetValue関数にはm_は指定されていませんnValメンバー変数がどのオブジェクトに属しているかという問題...実はコンパイラが隠れています.this->m_nVal = nVal;もちろん使用するときは、この変数の前に直接表示されるものを加えることができます.
しかし、thisポインタは、実際の開発では、オブジェクト自体を指すポインタを返してオブジェクトチェーン参照を実現したり、同じオブジェクトに値を付与したりすることを避けるために使用されることを意味します.たとえば
class Point
{
	public:
		Point( int x, int y ) : m_nX( x ), m_nY( y )
		{};
		void operator = (Point& pt)
		{
			//                    , ,        
			if( &pt == this )
			{
				m_nX = pt.m_nX;
				m_nY = pt.m_nY;
			}
		}
		//       
		Point& Move( int x, int y )
		{
			m_nX += x;
			m_nY += y;
			//       ,                 
			return *this;
		}
	private:
		int m_nX;
		int m_nY;
};

Point pt1(2, 4);
Point pt2(0, 0);
//           
pt1 = pt1;
//     ,                    ------------------------
pt1.Move( 1, 1 ).Move( 2, 4 );

ポインタ*:1)ポインタに1を加えたり減らしたりすると、ポインタが指すアドレスがオブジェクトのデータ型の長さを増やしたり減らしたりします.2)ポインタタイプの変換ポインタタイプの変換は予期せぬトラブルをもたらす可能性がありますが、goto文のように
int* pInt;
float* pFloat = ( float* )pInt;

この方法は直接的ですが、非常に乱暴です.彼はどんなタイプの間で変換することを許可します.また、このタイプの変換方式はプログラム文では識別しにくく、コードリーダーはタイプ変換の文を無視する可能性があります.これらの欠点を克服するために、C++は新しいタイプ変換オペレータstatic_を導入した.castは、上記のタイプの変換staticの代わりに使用されます.cast<タイプ説明子>(式)static_castポインタのタイプ変換-------------------------------------------------------------------------------
#include "stdafx.h"
#include "iostream"
using namespace std;

namespace Zeng
{
	class CTest_A
	{
	public:
		CTest_A()
		{}
		virtual void Print()
		{
			cout << "this's CTest_A's Print :" << endl;
		}
	};
	class CTest_B : public CTest_A
	{
	public:
		CTest_B()
		{}
		void Print()
		{
			cout << "this's CTest_B's Print :" << endl;
		}
	};
	class CTest_C
	{
	public:
		CTest_C()
		{}
		void Print()
		{
			cout << "this's CTest_C's Print :" << endl;
		}
	};
	class CTest_D
	{
	public:
		CTest_D() : m_iNum(14)
		{
		}
		void ConstPrint() const
		{
			cout << "ConstPrint print CTest_D m_iNum current value is :" << m_iNum << endl;
		}
		void Print()
		{
			cout << "Print print CTest_D m_iNum current value is :" << m_iNum << endl;
		}
		int m_iNum;
	}; //     const_cast     
}

int _tmain(int argc, _TCHAR* argv[])
{
	cout << "CTest_B convert to CTest_A :" << endl;
	Zeng::CTest_B* B = new Zeng::CTest_B();
	Zeng::CTest_A* A = static_cast< Zeng::CTest_A* >( B );
	A->Print();


	cout << "
"; cout << "CTest_A convert to CTest_B :" << endl; Zeng::CTest_A* A2 = new Zeng::CTest_A(); Zeng::CTest_B* B2 = static_cast< Zeng::CTest_B* >( A2 ); B2->Print(); /* cout << "
"; cout << "CTest_B convert to CTest_C :" << endl; Zeng::CTest_B* B3 = new Zeng::CTest_B(); Zeng::CTest_C* C = static_cast< Zeng::CTest_C* >( B3 ); // the CTest_B has nothing to do with CTest_C, so this convert been an error ! B2->Print(); */ cout << "
"; cout << "CTest_B convert to CTest_C :" << endl; Zeng::CTest_B* B3 = new Zeng::CTest_B(); Zeng::CTest_C* C = reinterpret_cast< Zeng::CTest_C* >( B3 ); // reinterpret_cast should be convert CTest_B to CTest_C, C->Print(); cout << "
"; cout << "CTest_A dynamic_cast to CTest_B :" << endl; Zeng::CTest_A* A4 = new Zeng::CTest_A(); Zeng::CTest_B* B4 = dynamic_cast< Zeng::CTest_B* >( A4 ); // dynamic_cast CTest_B // B4->Print(); // ,dynamic_cast , NULL cout << "
"; cout << "CTest_B dynamic_cast to CTest_A :" << endl; Zeng::CTest_B* A5 = new Zeng::CTest_B(); Zeng::CTest_A* B5 = dynamic_cast< Zeng::CTest_A* >( A5 ); // dynamic_cast CTest_B B5->Print(); // ,dynamic_cast , static_cast int iNum = 14; int* pINum = &iNum; char* pCTest = "a"; /* pCTest = reinterpret_cast< int* >( pINum );*/ cout << "pINum point value is : " << *pINum << endl; // reinterpret_cast , pINum = reinterpret_cast< int* >( pCTest ); cout << "pINum point value is : " << *pINum << endl; cout << "
"; const int iNum2 = 14; const int* piNum = &iNum2; int* piValue = const_cast< int* >( piNum ); *piValue = 70; cout << "use operator const_cast current *piValue value is : " << *piValue << endl; cout << "use operator const_cast current *piNum value is : " << *piNum << endl; cout << "use operator const_cast current iNum value is : " << iNum2 << endl; cout << "
"; const Zeng::CTest_D CD; // CD.m_iNum = 70; // error C3892: “CD”: const Zeng::CTest_D* pCD = &CD; Zeng::CTest_D* pCD2 = const_cast< Zeng::CTest_D * >( pCD ); pCD2->m_iNum = 70; cout << "use const_cast operator as object :" << endl; cout << "pCD2 is not's const point, this point m_iNum value is" << endl; pCD2->Print(); cout << "CD is a class object, this object m_iNum value is" << endl; CD.ConstPrint(); // const class const cout << "pCD is a const point, this point m_iNum value is" << endl; pCD->ConstPrint(); return 0; }

二次ポインタの使用
	char* arrMouth[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
	char** pMouth = arrMouth;
	int nIndex;
	cout << "           : " << endl;
	cin >> nIndex;

	//     char*                
	char* pCurMonth = *( pMouth + ( nIndex - 1 ) );
	cout << "       : " << pCurMonth << endl;
	cout << "       : " << *pCurMonth << endl;

ポインタの関数での役割:1)関数のパラメータにポインタを使用すると、大きなデータを渡すときに関数呼び出しのオーバーヘッドを効果的に削減できます.
void SumArray( const int* pArray, int nArrayCount, int* nSum )
{
	*nSum = 0;

	//       
	for (int i = 0; i < nArrayCount; i++)
	{
		*nSum += *pArray;
		pArray++;
	}
}

int _tmain(int argc, _TCHAR* argv[])
{
	cout << "        :" << endl;
	int nArraySum;
	int iArray[5] = { 1, 2, 3, 4, 5};

	SumArray( iArray, 5, &nArraySum );
	cout << "     :" << nArraySum << endl;

	return 0;
}

 
2)ポインタを関数として返す値関数の戻り値がポインタの場合,この関数がポインタ型関数である.ポインタ型関数は、通常、いくつかのポインタ変数の値を取得するために使用されます.クラスにポインタタイプのメンバー変数を返します.関数としてポインタに値を返すことがよくあります.
char* GetName()
{
	return m_pName;
}

引用&:1)引用の本質は,変数の別名であり,通俗的には変数のあだ名である.変数の引用に対していかなる操作を行って、変数自身の操作に対して、あなたの小さい名前を呼んでも、あなたのあだ名を呼んでも、同じ人を呼んでいると思っています.
	cout << "use reference:" << endl;
	int nIntValue = 99999;
	int& rIntValue = nIntValue;
	cout << "rIntValue:" << rIntValue << endl;
	cout << "rIntValue memory address:" << &rIntValue << endl;
	cout << "nIntValue:" << nIntValue << endl;
	cout << "nIntValue memory address:" << &nIntValue << endl;

	rIntValue = 1;
	cout << "modify rIntValue after:" << rIntValue << endl;
	cout << "rIntValue memory address:" << &rIntValue << endl;
	cout << "current nIntValue:" << nIntValue << endl;
	cout << "nIntValue memory address:" << &nIntValue << endl;

	nIntValue = 8888;
	cout << "modify nIntValue after:" << nIntValue << endl;
	cout << "nIntValue memory address:" << &nIntValue << endl;
	cout << "current rIntValue:" << rIntValue << endl;
	cout << "rIntValue memory address:" << &rIntValue << endl;

 
2)関数パラメータで使用すると,伝達参照はこのパラメータを直接修正することができる.
void Increase( int& nVal )
{
	nVal += 1;
}

3つの関数パラメータと戻り値の方法:1)伝値とは、実際のパラメータの値を直接パラメータにコピーすることであり、パラメータの伝達形式が簡単で自然で、理解しやすく、コードの可読性が高い.
2)伝達ポインタとは、伝達すべきデータのポインタをパラメータとして伝達する効率が高く、同時に伝達パラメータを伝達することができる
3)伝引用は伝達するデータの引用をパラメータとして伝達する効率が高く、同時に伝出パラメータを伝達することができ、形式が自然である
異常処理異常の使用は、プログラムの性能を低下させるが、適切に使用すれば、プログラムの性能を向上させることもある.たとえば、関数のパラメータがポインタである場合、関数の入り口でこのポインタの有効性をチェックする必要があります.
double Divede( int a, int b )
{
	if ( 0 == b )
	{
		throw "      0 ";
	}
	return ( double )a / b;
}

	cout << "use exception deal : " << endl;
	try
	{
		Divede( 2, 0 );
		cout << "throw a exception : " << endl;
	}
	catch ( char* pMsg )
	{
		cout << "catch a exception : " << pMsg << endl;
	}
	catch (...)
	{
		cout << "catch a exception : " << endl;
	}

	cout << "is this appcation exit ? : " << endl;


名前空間namespace:主に複数の人が同時に開発する際に使用し、衝突を避ける
namespace Zeng
{
	class CTest
	{
	public:
		void Print()
		{
			cout << "this is namespace Zeng's Print" << endl;
		}
	};
}

	cout << "use namespace Zeng ? : " << endl;
	Zeng::CTest CZengText;
	CZengText.Print();

カスタムタイプの使用typedef:子孫の前にbyteを使用するとunsigned charを使用することになります
typedef unsigned char byte;

マクロの使用#define 1)簡単な使用#define MAXSIZE 100 2)マクロ直接割り当て配列
#define myInitArray(ArrayName, ArraySize, InitValue) byte ArrayName[ArraySize + 1] = InitValue

 
3)マクロでの定義関数
#ifndef SAFE_DELETE
#define SAFE_DELETE( p )		{			\
			if( NULL != p )				\
			{							\
				delete p; p = NULL;		\
				cout << "safe delete..." << endl; \
			} }
#endif

#ifndef SAFE_DELETE_ARRAY
#define SAFE_DELETE_ARRAY( p )		{			\
	if( NULL != p )				\
{							\
	delete[] p; p = NULL;		\
	cout << "safe delete[]..." << endl; \
} }
#endif


	Zeng::CTest* CZengText2 = new Zeng::CTest;
	SAFE_DELETE( CZengText2 );


constでデータを保護する1)constで定数を定義する
const int number = 1;	//             1
const int* pNumber;	//          ,              ,       
int const* pNumber;	//           ,    
int* const pNumber = &number;		//           ,      
const int* const pNumber = &number;//             ,                 
const int& number = number; //           

2)const実*の位置判断によると、constが*の左側にあると、constがintを修飾していることを示し、このポインタが指すint変数の値は修正できず、ポインタ自体の値は可変である.constが*の右側にある場合、constが修飾しているのはポインタであり、このポインタの値は宣言後に変更できないため、このようなポインタを宣言する際に初期値を付与する必要があり、このポインタが指すint変数の値は可変である.
3)関数パラメータにconstを加えると,これは単なる伝達パラメータであり,関数全体で修正できないことを示す.
4)修飾クラスメンバー関数クラスのメンバー関数を宣言するとき、最後にconst修飾を付けると、このメンバー関数内でオブジェクトのデータを変更できないことを示します.このパターンは、「オブジェクトデータ制度」のアクセスパターンを表すのによく用いられる.
namespace Zeng
{
	class CTest
	{
	public:
		void Print() const
		{
			m_nValue = 1;
			cout << "this is namespace Zeng's Print" << endl;
		}
	private:
		int m_nValue;
	};
}

//プロンプトerror:error C 2166:左値指定constオブジェクト