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.一个模板的模板参数表与其模板成员的模板参数表不能组合在一起。