1.使用類或者結構體時,再定義的後面要添加";"
class Flyingtime
{
......
};
struct Flyingtime
{
.......
};
2.在windows下使用include包含相對路徑下的文件要使用"/"
例如在flyingtime下有如下文件夾:
header、source、information等
如果要在source文件夾下的test.cpp要用到header下的test.h文件
#include "../header/test.h"
3. 在類中聲明"static"類型變量,在類的定義中就不能再次使用"static"了
#ifndef TEST_H
#define TEST_H
class test
{
public:
test();
~test();
static int const test_int() const;
private:
static int int_arg;
};
#endif
#include <iostream>
using std::cout;
using std::endl;
#include "test.h"
int test::int_arg=0;
test::test()
{
int_arg++;
cout << "test class start!" << endl;
}
test::~test()
{
int_arg--;
cout << "test class end!" << endl;
}
int const test::test_int() const
{
cout << "static argument is : " << int_arg << endl;
return int_arg;
}
4.類沒有對象也可以訪問其靜態成員變量,但必須用靜態成員函數進行訪問
#include <iostream>
using std::cout;
using std::endl;
#include "test.h"
void main()
{
test *abc= new test();
abc->test_int(); //此時可以用abc->int_arg來獲取靜態變量的值,因爲test類的對象abc存在
delete abc;
abc=0;
test::test_int(); //此時必須用類的靜態成員函數來獲取靜態變量的值
}
5. 在一些信息安全較高的地方最好使用“代理類”
假設一個類進行信息加密Encrypt,他的一個代理類EncryptPtr
encrypt.h
#ifndef ENCRYPT_H
#define ENCRYPT_H
#region
class Encrypt
{
public:
Encrypt(FILE *,FILE *);
~Encrypt();
void Encrypt_Code();
private:
int m_Encrypt;
};
#endregion
#endif
encrypt.cpp
#include <iostream>
using std::cout;
using std::endl;
#include <ctime>
#include <cstdlib>
#include "encrypt.h"
Encrypt::Encrypt(FILE *fpinput,FILE *fpoutput)
{
assert(fpinput);
assert(fpoutput);
srand(time(0));
m_Encrypt=rand();
}
Encrypt::~Encrypt()
{
m_Encrypt=0;
}
void Encrypt::Encrypt_Code()
{
}
encrypt_ptr.h
#ifndef ENCRYPT_PTR_H
#define ENCRYPT_PTR_H
class Encrypt;
class Encrypt_Ptr
{
public:
Encrypt_Ptr(FILE *,FILE *);
~Encrypt_Ptr();
privat:
Encrypt_Ptr *cpEncrypt;
};
#endif
encrypt_ptr.cpp
#include "encrypt.h" //被代理類的頭文件
#include "encrypt_ptr.h" //代理類的頭文件
Encrypt_Ptr::Encrypt_Ptr(FILE *fpinput,FILE *fpoutput)
:cpEncrypt(new Encrypt(fpinput,fpoutput))
{
cpEncrypt->Encrypt_Code();
}
Encrypt_Ptr::~Encrypt_Ptr()
{
delete cpEncrypt;
}
7.靜態成員函數只能訪問靜態成員變量,將靜態成員函數聲明爲"const"是語法錯誤!
因爲靜態成員函數是獨立於類而存在的,也就是說類並不給其靜態成員函數傳遞this指針,這就意味着靜態成員函數只能看到靜態成員變量,而類中的其他成員變量它是看不到的。成員函數的const實際上也是修飾的this指針,所以將靜態成員函數聲明爲"const"是語法錯誤!
8.可以重載的操作符有:
+ - * / % ^ & | ~ ! = > < += -= *= /= %= ^= &= |= << >>
>>= <<= == != <= >= && || ++ -- ->* ' -> [] () new delete new[] delete[]
不能被重載的操作符有:
. .* :: ?: sizeof
9.什麼時候定義類成員操作符重載,什麼時候定義非類成員操作符重載?
(1)如果一個重載操作符是類成員,那麼只有當跟它一起使用的左操作數是該類對象時,它纔會被調用,如果該操作符的左操作數必須是其他類型,那麼重載操作符必須是非類成員操作符重載。
(2)C++要求,賦值(=),下標([ ]),調用(())和成員訪問箭頭(->)操作符必須被指定爲類成員操作符,否則錯誤。
10.當做重載操作符操作時,如果類的實例對象出現在重載操作符的右邊時,最好將該重載操作符的函數聲明爲友元函數
#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
using::ostream;
using::istream;
class Array
{
public:
Array(int=10);
Array(const Array &);
friend ostream &operator <<(ostream &,const Array &);
friend istream &operator >>(istream &,Array &);
Array operator =(const Array &);
bool operator ==(const Array &) const;
bool operator !=(const Array &) const;
int operator [](int subscript);
int GetSize();
~Array();
private:
int m_size;
int *lp_array;
static int m_obj_counter;
};
#endif
#include <iostream>
using std::cin;
using std::cout;
#include <iomanip>
using std::setw;
#include <cstdlib>
#include <cassert>
#include "array.h"
Array::Array(int size)
{
m_size=size>0 ? size : 10;
l p_array=new int[m_size];
assert(lp_array!=0);
}
Array::Array(Array &rf_array)
:m_size=rf_array.m_size
{
lp_array=new int[m_size];
for(int i=0;i<m_size;i++)
{
lp_array[i]=rf_array.lp_array[i];
}
}
Array::~Array()
{
delete[] lp_array;
m_size=0;
}
ostream &operator <<(ostream &output,const Array &rf_array)
{
for(int i=0;i<rf_array.m_size;i++)
{
output << rf_array.p_array[i] << setw(10);
if(rf_array.m_size%5==0)
output << endl ;
}
if(rf_array.m_size%5!=0) output << endl;
return output;
}
istream &operator >>(istream &input,Array &rf_array)
{
for(int i=0;i<rf_array.m_size;i++)
{
input >> rf_array.lp_array[i] ;
}
return input;
}
Array &Array::operator=(const Array &rf_array)
{
if(&rf_array!=this)
{
if(m_size!=rf_array.m_size) m_size=rf_array.m_size;
delete[] lp_array;
lp_array=new int[m_size];
assert(lp_array!=0);
for(int i=0;i<m_size;i++)
{
lp_array[i]=rf_array.lp_array[i];
}
}
return *this;
}
int &Array::operator[](int subscript)
{
assert(subscript>=0&&subscript<m_size);
return lp_array[subscript];
//在實際程序中驗證該返回值是正確的。。。 cout << arrayobject[intobject] or
//arrayobject[intobject]=intobject 都是正確的
}
bool Array::operator ==(const Array &rf_array) const
{
if(rf_array.m_size!=m_size) return false;
for(int i=0;i<m_size;i++)
{
if(lp_array[i]!=rf_array.lp_array[i]) return false;
}
return true;
}
bool Array::operator !=(const Array &rf_array) const
{
if(rf_array.m_size!=m_size) return true;
for(int i=0;i<m_size;i++)
{
if(lp_array[i]!=rf_array.lp_array[i]) return true;
}
return false;
}
#include <iostream>
using std::cout;
using std::cin;
#include "array.h"
bool main()
{
Array a(8),b(6);
cin >> a ;
cin >> b ;
cout << a ;
cout << b;
if(a!=b) a=b;
cout << a;
cout << b;
if(a==b) return true;
return false;
}
比較有疑問的那部分代碼的反彙編代碼如下:
return p_array[subscript];
004130C9 mov eax,dword ptr [this]
004130CC mov ecx,dword ptr [eax+4]
004130CF mov edx,dword ptr [subscript]
004130D2 lea eax,[ecx+edx*4]
可以看出這裏 return p_array[subscript]就是返回它的指針
11.派生類的對象就是基類對象,但反過來則不成立;如果想讓基類對象轉換成派生類對象必須進行顯式的轉換
如果將上面的:
template<class T1>
template<class T2>
寫成:
template <class T1,class T2>即爲錯誤,因爲它們兩個的作用域是完全不同的
class a
{
public:
a();
~a();
protected:
int x;
int y;
};
a::a()
:x(0),y(0)
{}
a::~a()
{}
class b : public a
{
public:
b();
~b();
private:
int count;
};
b::b()
:a()
{}
b::~b()
{}
int main()
{
a *cp_a=0,a_obj;
b *cp_b=0,b_obj;
cp_a=&a_obj;
cp_b=&b_obj;
cp_a=&b_ojb;
cp_b=static_cast<b *>&a_obj;
cp_b=static_cast<b *>cp_a;
return 0;
}
12.基類的構造函數跟賦值操作符不能被派生類函數繼承,但派生類的構造函數和賦值操作符可以調用基類的構造函數和賦值操作符。
13.關於位段的一些問題:
struct test
{
unsigned a : 2 ;
unsigned b : 4 ;
unsigned c : 2 ;
};
(1.)位段操作與機器有關,有些機器允許位段跨越字邊界,而有的不可以;
(2.)位段成員的類型只能是unsigned或者int;
(3.)試圖取位段的地址或者試圖訪問位段中單獨的位都是錯誤的操作;
14.在迭代器中添加新的元素可能會使迭代器失效,尤其存儲end返回的迭代器。
因爲end返回的迭代器並非是該容器的最後一個迭代器,而是該容器的最後一個迭代器的下一個
#include <iostream>
#include <vector>
int main()
{
std::vector<int> v;
std::vector<int>::iterator first=v.begin(),
last=v.end();
while(first != last)
{
first = v.insert(first,66);
++first;
}
}
15.應該保持成員初始化列表中成員列出的順序和它們在類中聲明的順序相同,因爲類成員是按照它們在類裏聲明的順序進行初始化的,和它們在成員列表中列出的順序沒有一點關係。
例如:
#ifndef ARRAY_H
#define ARRAY_H
#include <cstdlib>
#include <vector>
template<typename T>
class Array
{
public:
Array(int lowBound,int highBound);
private:
vector<T> data;
size_t size;
int mLow;
int mHigh;
};
template <typename T>
Array<T>::Array(int lowBound,int highBound)
:mLow(lowBound),mHigh(highBound),size(highBound-lowBound+1),data(size)
{}
#endif
這裏data的大小並不確定,因爲首先初始話的是vector<T> data(size),而此時的size並沒有被初始化。正確的例子如下:
#ifndef ARRAY_H
#define ARRAY_H
#include <cstdlib>
#include <vector>
template<typename T>
class Array
{
public:
Array(int lowBound,int highBound);
private:
int mLow;
int mHigh;
size_t size;
vector<T> data;
};
template <typename T>
Array<T>::Array(int lowBound,int highBound)
:mLow(lowBound),mHigh(highBound),size(highBound-lowBound+1),data(size)
{}
#endif
16.注意賦值運算以及拷貝構造函數,尤其是存在繼承的關係中
template<typename T>
class Base
{
public:
Base(const Base& default)
:mData(default.mData)
{}
Base& operator = (Base& default)
{
if(this == & default)
//這裏檢查是否對自身賦值
return *this;
mData = default.mData;
return *this;
}
private:
T mData;
};
template <typename T>
class Child : public Base<T>
{
public:
Child(const Child& default)
:Base(default),mSubData(default.mSubData)
{
Child& operator=(const Child& default)
{
if(this == &default)
//檢查是否是對自身賦值
return *this;
static_cast<Base&>(*this) = default;
mSubData=default.mSubData;
return *this;
}
private:
T mSubData;
}
17.如果派生類中私有繼承基類,並且在派生類中在調用基類中的函數可以用using顯式的聲明。
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
class a
{
public:
void showa()
{
cout << "a.show/n";
}
};
class b : private a
{
public:
using a::showa;
void showb()
{
cout << "b.show/n";
showa();
}
};
void main()
{
b name;
name.showb();
int i;
cin >> i;
return;
}
18.請看上面的例子,基類a並沒有實現virtual ~a(),爲了讓以a爲基類的派生類不產生錯誤,派生類只能實現私有繼承。之所以這麼做有以下原因:
(1)不實現virtual ~a(),是爲了不再增加派生類的體積,如果實現virtual ~a(),將引入vtab。
(2)之所以在派生類中私有繼承基類,是爲了在派生類中不能直接調用基類的析構函數,如:
a *pa;
b *pb=new b;
pa=pb; //加入基類的私有繼承這裏就會出現錯誤
delete pa; //這裏不加入virtual ~a()將會出現錯誤,我們把a私有繼承,那麼這裏就不會出現錯誤!因爲a的析構函數是私有的。
19.從一個類模板生成的每個類都將得到類模板中每個static成員的一個副本。
摘自《C++程序設計(特別版)》,還沒有完全明白它的意思,有一個例子:
20.一個模板的模板參數表與其模板成員的模板參數表不能組合在一起。