memo‎ > ‎

C/C++

C言語
・ビットフィールドの例
 struct {
  unsigned b: 1;//通常、unsignedかint
} Boolean;
・#line ディレクティブは行番号(__LINE__)とファイル名(__FILE__)を変更する
 #line 100 "ファイル名" 
・#error ディレクティブはコンパイラを中止し、エラーを出力する
・文字列か演算子#は、マクロ関数内で文字列に置き換える
・トークン結合演算子##は、マクロ関数内で右辺と左辺を接合する
・malloc(size * num) と calloc(num, size) は同じ。ここで num は要素数、size は要素のバイトサイズ
・scanf関数の詳細な仕様を覚えるのはやめよう
・可変長引数に使われる va_arg(), va_start(), va_end() マクロは「定義へ移動」で辿っていくと以下のようになる 
 va_start(valist arg_ptr, prev_param)va_arg(valist arg_ptr, type)va_end(valist arg) 
 1.stdarg.h _crt_va_start _crt_va_arg _crt_va_end
 2.vadefs.h _crt_va_start(ap,v) 
 ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
 _crt_va_arg(ap,t)   
 ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
 _crt_va_end(ap)
 ( ap = (va_list)0 )
ここで _INTSIZEOF と _ADDRESSOF はこのようになっている
  #define _ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )
  #define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
ちなみに va_list はただの char ポインタ
  typedef char *  va_list;
va_list は va_start() と va_art() が呼び出されるたびに、int サイズ単位で次の引数ポインタへ移動しているようだ
va_end() は単に va_list にNULL を設定しているだけ

C++言語
sizeof(this) は間違い。正しくは sizeof(*this)
・グローバルオブジェクトはプログラム実行時にコンストラクタが呼び出され、ローカルオブジェクトは宣言部で呼び出される
・デストラクタには引数を渡すことができない
・戻り値として参照を返すことができる
#include <iostream>
using namespace std;
int g;
int& Ref() {
  return g;
}
int main() {
  Ref() = 2;
  cout << g << endl;

  return 0;
}
・コピーコンストラクタは、関数にオブジェクトを値渡しする時と関数から呼び出しもとにオブジェクトを値渡しする時にも呼び出される。代入では作用しない
・デフォルト引数は関数のプロトタイプまたは定義のいずれかで行うことができる。両方で指定することはできない
・オーバーロードされた関数のポインタは、ポインタの宣言と一致させて取得できる
・派生クラスと基底クラスのメンバ名が衝突した場合は、基底クラスをスコープで指定して、基底クラスメンバを呼び出せる
・基底クラスのコンストラクタ引数は派生クラスのコンストラクタで指定する
・コンストラクタは基底クラスから派生クラスの順で呼び出され、デストラクタは派生クラスから基底クラスの順で呼び出される
・クラス名を宣言することにより、クラス名を認識することができる。その場合、定義されるまでメンバ名は使えない
・フレンド関数は非公開メンバへアクセスできる。クラス内で friend キーワードで関数を宣言し、関数定義でクラスにアクセスする
・クラス内で friend キーワードでフレンドクラスを宣言できる。宣言されたクラスは宣言したクラスに自由にアクセスできる
・仮想基底クラスは覚えなくていいかな?かな?
・派生クラスのポインタを基底クラスポインタに代入できる。この場合、メンバ名が衝突しているときは基底クラスメンバにアクセスする
・仮想関数による動的なポリモーフィズムをオーバーライドと呼び、仮想関数を含むクラスをポリモーフィッククラスと呼ぶ
・基底クラスのデストラクタを呼び出した場合、派生クラスのメンバ関数を呼び出せない場合がある
typename キーワードはテンプレート定義内で未知の識別子であることを指定する。代わりに class キーワードを用いることもできる
・VC++では関数が返すことができる例外を指定できないようだ。void Func() throw ( char ) { ・・・ }
・例外の catch ブロックでオペランドなしの throw を実行した場合、catch ブロックの型の例外が発生したとみなされる
・C++ではオブジェクトのアップキャストは暗黙的に行えるが、ダウンキャストは dynamic_cast 演算子を使う
・名前空間はネストできる
・無名名前空間は同一ファイルのみからアクセスできる。他のファイルから extern を用いてもアクセスできない。
 C++では static を用いるより無名名前空間を用いることが推奨される
const キーワードを指定したメンバ関数はそのオブジェクトのメンバ変数の値を変更できない。
 但し、mutable キーワードのついたメンバ変数は変更できる
const オブジェクトは非 const メンバ関数を呼び出すことができない
・コンストラクタ引数は1つの場合代入演算子を使うことができるが、explicit キーワードを指定すれば代入演算子を使うことはできない
・C++には同じスコープ内で有効な無名共用体がある。グローバル無名共用体は static キーワードを指定する
・派生クラスの仮想関数を定義した場合に、基底クラスの関数を呼び出したい場合はスコープを利用する。(C#では base キーワード、Java では super キーワードが使える)
#include <iostream>

class base {
public:
  virtual void Print() { std::cout << "base" << std::endl; }
};

class sub : public base {
public:
  virtual void Print() { std::cout << "sub" << std::endl; }
  void Print2() { Print(); }
  void Print3() { base::Print(); }
};

int main(void)
{
  base* b = new sub();
  sub*  s = new sub();

  b->Print();       // sub
  b->base::Print(); // base
  s->Print2();      // sub
  s->Print3();      // base

  return 0;
}

Effective C++、良いC++コードを書くには
mutable メンバ変数は const メンバ関数内で値を変更することができる。論理的普遍性を持ちたい場合有効
・コンストラクタでは、代入ではなく、メンバ初期化リストを使うことで、二重の初期化を防ぎ効率がよくなる
・初期化順序を決められない、異なる翻訳単位の「ローカルでない静的オブジェクト」の代わりに、関数内の static オブジェクトに置き換える
・純粋仮想関数を含む基底クラスは仮想デストラクタにする

その他
文字コード
 C表記 10進数 16進数 機能
 \t 90x09  次のタブ位置まで移動する
 \n 100x0A 次の行に移動する
 \f 120x0C 改ページする
 \r 130x0D 行の先頭に移動する
 \\ 92 0x5C 
 + 43 0x2B 
 - 45 0x2D 
 \\ 92 0x5C