C++メモ(上)
8916 ワード
void *
については、この点がより際立っている.Cは、1つのタイプのポインタを別のタイプに勝手に割り当てることは許されないが、void *
によって実現することは許される.たとえば、bird* b;
rock* r;
void* v;
v = r;
b = v;
C++では許可されていません.そのコンパイラはエラーメッセージを与えます.本当にそうしたい場合は、マッピングを明示的に使用し、コンパイラと読者に通知する必要があります.struct X; // Declaration(incomplete type spec)
struct Y
{
void f(X *memx);
void g(X memx); // not allowed, the size of X is unknown.
};
ここでf(X*)はXオブジェクトのアドレスを参照しています.これは問題ありませんが、void g(X memx);
ではだめです.コンパイラはエラーを報告します.コンパイラは、渡されたオブジェクトタイプのサイズにかかわらず、アドレスをどのように渡すかを知っているため、このアドレスのサイズは一定です.オブジェクト全体を転送しようとすると、コンパイラはXのすべての定義を知って、そのサイズとどのように転送するかを決定する必要があります.これにより、プログラマはY::g(X)のような関数を宣言できません.friend
と宣言された場合、クラスのメンバー関数ではありませんが、クラスのプライベートメンバーを変更でき、クラスの定義にリストされなければならないため、特権関数とみなすことができます.このクラスの定義は、クラスのプライベート部分を変更できる関数を知る権限に関する情報を提供します.したがって、C++は完全なオブジェクト向け言語ではなく、ハイブリッド製品にすぎません.friend
キーワードは、部分的な突発的な問題を解決するために使用されます.この言語が不純であることも示しています.結局C++言語の設計は実用のためであり、理想の抽象を追求するのではない.cout<//
cout << hex << "0x" << i; // 16
cin>>ws; //
iostream.hはまた以下の操縦演算子を含む:どのように私たち自身の操縦演算子を創立しますか?私たちは自分の操作演算子を構築したいかもしれませんが、これはかなり簡単です.endlのようなパラメータを持たない操作演算子はただの関数であり、この関数はostreamをそのパラメータとして参照する.endlに対する宣言は、ostream& endl(ostream&);
例です.このストリームをリフレッシュせずに改行を生成します.nlはendlを使用するよりも優れていると考えられています.後者は常に出力ストリームを空にしているため、実行障害を引き起こす可能性があります.ostream& nl(ostream& os) {
return os << "
";
}
int main() {
cout << "newlines" << nl << "between" << nl << "each" << nl << "word" << nl;
return 0;
}
const bufsize=100;
char buf[bufsize];
と書くと、合理的なことをしたように見えますが、これは誤った結果を得ることになります.bufsizeはストレージの場所を占有するため、Cコンパイラはコンパイル時の値を知らない.C言語では、const bufsize;
がC++に書かれているのは間違っていますが、Cコンパイラは、別の場所にストレージ割り当てがあることを示す宣言として使用します.Cデフォルトconstは外部接続なので、C++デフォルトcosntは内部接続です.このように、C++でCと同じことをしたい場合は、externで接続を外部接続に変更する必要があります.extern const bufsize;//declaration only
という方法もC言語で使用できます.注意:C言語で制限子constを使用するのはあまり役に立ちません.定数式でも(コンパイル中に求めなければなりません).名前付きの値を使用するにはconstを使用してもあまり役に立ちません.Cプログラマにプリプロセッサでdefineを使用させる.class bob {
const size = 100; // illegal
int array[size]; // illegal
}
の結果はもちろんコンパイルに失敗しました.why?constはクラスオブジェクトに格納空間割り当てを行っているため,コンパイラはconstの内容が何であるかを知ることができないため,コンパイル期間の定数として使用することはできない.これはクラス内の定数式にとってconstがCのように機能しないことを意味する.クラス内のconstは「この特定のオブジェクトの寿命期間内で、クラス全体にとってこの値は変わらない」という意味です.では、定数式に使用できるクラス定数をどのように構築しますか?一般的な方法は、インスタンスを持たないタグのないenumを使用することです.列挙されたすべての値はコンパイル時に確立されなければならない.クラスにとってローカルであるが、定数式はその値を得ることができる.このように、class bob {
enum { size = 100 }; // legal
int array[size]; // legal
}
がenumを使用すると、オブジェクト内の記憶空間を占有することはなく、列挙定数はコンパイル時にすべて求められることが一般的に見られる.列挙定数の値:enum { one=1,two=2,three};
class X {
int i;
public:
int f() const;
}
ここでf()はconstメンバー関数であり、constクラスオブジェクトのみがこの関数を呼び出すことができることを示します(constオブジェクトは非constメンバー関数を呼び出すことができません).オブジェクトのいずれかのメンバーを変更したり、非constメンバー関数を呼び出すと、コンパイラはエラーメッセージを発行します.キーワードconstは同じ方法で定義に繰り返し表示されなければなりません.そうしないと、コンパイラはそれを異なる関数と見なします.int X::f() const { return i;}
メンバーデータを変更しない関数はconst関数として宣言され、constオブジェクトで使用できます.注意:コンストラクション関数とコンストラクション関数はconstメンバー関数ではありません.初期化とクリーンアップ時にオブジェクトが常に変更されるためです.###引用:constメンバー関数でメンバーを変更する方法--ビット単位とメンバー単位const####constメンバー関数を作成したい場合、オブジェクトでデータを変更したい場合はどうすればいいですか?これは、ビット別constとメンバー別constの違いに関係します.ビット別constは、オブジェクト内の各ビットが固定されているため、オブジェクトの各ビットイメージが変更されないことを意味します.メンバーconstでは、オブジェクト全体が概念的に変わらないが、あるメンバーが変化する可能性があるという意味です.コンパイラは、オブジェクトがconstオブジェクトであることを通知されると、そのオブジェクトを保護します.
ここではconstメンバー関数でデータメンバーを変更する2つの方法について説明します.-1つ目の方法は、「強制変換const」と呼ばれる過去のものとなっている.かなり奇妙な方法で実行されます.this(このキーワードは現在のオブジェクトのアドレスを生成します)を取り、現在のタイプのオブジェクトへのポインタに強制的に変換します.これはすでに私たちが必要とするポインタのようですが、constポインタなので、演算で定数性を取り除くことができます.次に例を示します.
class Y {
int i, j;
public:
Y() { i = j = 0; }
void f() const;
};
void Y::f() const {
//! i++; // error
((Y*)this)->j++; // ok , cast away const feature.
}
, ,** **。 :**this const , **, , ( ), 。
-2つ目の方法は、クラス宣言でキーワード
mutable
を使用して、特定のデータメンバーがconstオブジェクトで変更できることを指定する方法でもあります. class Y {
int i;
mutable int j;
public:
Y() { i = j = 0; }
void f() const;
};
void Y::f() const {
//! i++; // error
((Y*)this)->j++; // ok , mutable.
}