Effective C++読書ノート6


4設計と宣言
条項18:インタフェースが正しく使用されやすく、誤用されにくい
条項19:設計classは設計typeのようだ
条項20:pass-by-reference-to-constでpass-by-valueを置き換える
by value方式はby reference方式よりコストが大きい.クラスのコピーコンストラクタが呼び出されるため、破棄時にコンストラクタが呼び出され、クラス内にクラスがある場合、対応するクラスのコピーコンストラクタとコンストラクタが呼び出されるため、by value方式はコストが非常に大きい.
また、by value方式では、派生クラスオブジェクトがby value方式で伝達され、ベースクラスオブジェクトと見なされると、ベースクラスのコピーコンストラクション関数が呼び出され、「このオブジェクトの動作が派生クラスオブジェクトのようになる」という特化した性質が切断され、ベースクラスオブジェクトが1つしか残っていません.
class Window{
public:
	std::string name() const;
	virtual void display() const;
};

class WindowWithScrollBars: public Window{
public:
	virtual void display() const;
};

関数を書いてウィンドウ名を印刷し、ウィンドウを表示するとします.次はエラーの例です.
void printNameAndDisplay(Window w){
	
	std::cout << w.name();
	w.display();
}

上記の関数にWindowWithScrolBarsオブジェクトを渡すと、上記の関数内でdisplay呼び出しを呼び出すのは常にWindow::displayである.
切断問題を解決する方法は、by reference-to-constでwを伝達することである.
C++コンパイラの下部を覗くと、referenceはポインタで実現されることが多いため、pass by referenceは通常、ポインタが本当に伝達されることを意味します.したがって、オブジェクトが内蔵タイプに属している場合、pass by valueはpass by referenceよりも効率的です.組み込みタイプでは、pass-by-valueまたはpass-by-reference-to-constを使用する機会がある場合、pass-by-valueを選択するのは無理ではありません.この忠告はSTLの反復器と関数オブジェクトにも適用される.習慣的にpassed by valueとして設計されているからだ.(??????????)
一般的にpass-by-valueが高価ではない唯一のオブジェクトは、内蔵タイプとSTLの反復器と関数オブジェクトであると合理的に仮定できます.他のものはすべて本条項の忠告を守って、できるだけpass-by-reference-to-constでpass-by-valueを交換してください.
覚えておいてください:
1.pass-by-valueをできるだけpass-by-reference-to-constで置き換える.
2.上記のルールは、内蔵タイプやSTLの反復器や関数オブジェクトには適用されません.彼らにとってpass-by-valueは往々にして適切である.
条項21対象を返さなければならない場合、戻り期間referenceを妄想しないでください.
referencesは、実際には存在しないオブジェクトを指す可能性があります.
class Rational{
	
public:
	Rational(int numerator = 0, int denominator = 1);
	
private:
	int n, d;
	friend const Rational operator* (const Rational& lhs, const Rational& rhs);
};

operator*のインプリメンテーション内にstackオブジェクトが返される場合、関数が返されるとオブジェクトは存在しません.heapオブジェクトを返すと、deleteを忘れるリスクがあります.
Rationl w, x, y, z;
w = x * y * z;

ここで、同じ文でoperator*が2回呼び出されるため、newを2回使用するとdeleteが2回必要になります.しかし、operator*の使用者にdelete呼び出しを行う合理的な方法はありません.operator*の後悔のreferenceの背後に隠されているポインタを取得する合理的な方法がないからです.static Rationalオブジェクトを使用できると言われています.
const Rationl& operator* (const Rational& lhs, const Rational& rhs){
	
	static Rational result;
	result = ...;
	return result;
}
はstaticオブジェクトを使用したすべての設計のように、マルチスレッドセキュリティに対する疑問をすぐに引き起こします.さらに、より深い欠陥を考慮し、以下の完全に合理的な顧客コードを考慮します.
bool operator== (const Rational& lhs, const Rational& rhs);
Rational a, b, c, d;
if((a*b) == (c * d)){
	
}else{
	
}

    :
if(operator==(operator*(a, b), operator*(c, d)))

operator==operator*内部で定義されているstatic Rationalオブジェクトの値をoperator*内のstatic Rationalオブジェクトの値と比較するように要求されますが、等しくなければおかしいですね.
新しいオブジェクトを返さなければならない関数の正しい書き方は、関数に新しいオブジェクトを返させることです.
inline const Rational operator* (const Rational& lhs, const Rational& rhs){
	
	return Rational(lhs.n * rhs.n, lhs.d * rhs.d);
}

覚えておいてください:
pointerまたはreferenceがlocal stackオブジェクトを指すか、referenceがheap-allocatedオブジェクトを指すか、pointerまたはreferenceがlocal staticオブジェクトを指すかを絶対に返さないでください.このようなオブジェクトが同時に複数必要になる可能性があります.
条項22:メンバー変数をprivateとして宣言メンバー変数をprivateとして宣言するメリット:
1.カッコを付けるかどうかを考慮する必要はありません.privateの場合、アクセス変数には必ずカッコを付ける必要があります(構文整合性)
2.関数を使用すると、メンバー変数の処理をより正確に制御できます.
class AccessLevels{
	
public:
	int getReadOnly() const {return readOnly;}
	void setReadOnly(int value) {readWrite = value;}
	int getReadWrite() const {return readWrite;}
	void setWriteOnly(int value) {writeOnly = value;}
private:
	int noAccess;
	int readOnly;
	int readWrite;
	int writeOnly;
};

3.パッケージ:
class SpeedDataCollection{
	
public:
	void addValue(int speed);
	double averageSoFar() const;
};

メンバー関数averageSoFarの設計:クラス内でメンバー変数を設計し、これまでのすべての速度の平均値を記録する方法です.関数が呼び出されると、そのメンバー変数を返すだけでいいです.これにより、計算は不要ですが、多くの計算速度に関連するメンバーに空間を割り当てる必要があるため、関数の反応速度が速くなります.
2つ目は、関数呼び出し時に計算されるため、関数の反応速度は遅くなりますが、オブジェクトは小さくなります.
2つの異なる方法では、メンバー変数を関数インタフェースの背後に隠す必要があり、「すべての可能な実装」に弾力性を提供します.
覚えておいてください:
1.メンバー変数をprivateとして宣言することを忘れないでください.これにより、お客様がデータにアクセスする一貫性が付与され、アクセス制御を細かく区分することができ、制約条件が保証され、class作成者が弾力性を充実させることができます.
2.protectedはpublicよりパッケージ性があるわけではありません(????