effective c++笔记

//类常量(有的编译器不支持,支持的话只对整形有效)
class mater{
private:
 static const int mn=5;
 int scores[mn];  
};
//enum代替整形常量
class mater{
private:
 enum {mn=5};
 int scores[mn];  
};

//zhe same
const Myclass *pw
Myclass const *pw

//stl的指向的东西不被改变const_iterator
std::vector<int> vec;
...
const std::vector<int>::iterator iter=vec.begin();//只是指向位置不能改变
std::vector<int>::const_iterator iter=vec.begin();//指向的东西不能改变

//const成员函数
相当于传入的this对象调用时为const的,及不能改动对象
只读的函数设为const很好
class mater{
public:
 const int getInt()const;
 int getInt();
private:
 int jj;
};
这里有一个很重要的问题(非const--->const可以,const--->非const不可以)
两个成员函数如果只是const不同是允许重载的,这是很自然的

//mutable关键字
由mutable声明的成员变量即使在onst成员函数内也允许改变

//const_cast
把const--->非const
class mater{
public:
 const int getInt()const
 {
  return jj;
 }
 int getInt()
 {
  return const_cast<int>(static_cast<const mater&>(*this).getInt())
 }
private:
 int jj;
};
static_cast<const mater&>(*this).getInt()
为this加上const调用const int getInt()const完成一次定义两次用

//初始化时间
class mater{
public:
 mater()
 :jj(0)
  mm(0)
 {}
private:
  int jj;
  int mm;
}
//baseclass最先初始化,然后是够造函数的声明顺序

//static 对象是从构造出来到程序结束一直存在的
//non-local static对象是没有一个确定的初始化时间的
解决方法是把non-local static对象变为static对象

//empty class
class mater{};
相当于
class mater{
public:
 mater(){}
 mater(const mater& mm){}
 ~mater(){}//non virtual
 
 mater& operator=(const mater &mm){}
};
//当任何一个需要调用时,它们就会被编译器建立
//对有reference成员和const成员的class他不会自动生成operator=
//若baseclass的operator=被声明为private,子类不会自动生成operator=

//阻止子类创建一些专有函数,可在父类里面声明它们为private,并不定义它们
private: 
 void *operator new[](unsigned nSize);
 
//non-virtual 析构函数
当子类通过父类的指针被delete掉的时候,如果父类的析构函数是non-virtual,执行时子类的部分并没有销毁
美其名曰:局部销毁

//对于不希望被继承的类
virtual函数最好不加
其实一个建议,只要看析构函数是不是virtual的,就能判断这个类能不能继承

//给baseclass一个virtual析构函数
适用于通过baseclass的接口处理derivedclass的对象
只要不是用于多态就不该声明一个virtual析构函数

//不要让异常逃离析构函数

//不要在构造函数和析构函数里面调用virtual成员函数
在构造函数里面调用的virtual成员函数属于父类,没有完成多态的任务
因为父类构造总是在子类前

//自己定义的copy struct和operator=不会对父类的成员进行操作
MaterD& MaterD::operator=(const MaterD &rhs)
{
 MaterS::operator=rhs;
 mm=rhs.mm;
 return *this;
}

//stl动态指针不对数组做处理

//一个经典指针类std::tr1::shared_ptr,资源可分配给多个指针
typedef std::tr1::shared_ptr<Mutex> mutexPtr;
class Lock
{
public:
 explicit Lock(Mutex *pm)
 :mutexPtr(pm,unlock)
 {
  lock(mutex.get());
 }
private:
 std::tr1::shared_ptr<Mutex> mutex;
};
这里的unlock为mutex的第二个参数为deleter,当记数为0的时候调用

//对封装来讲提供原始资源的访问是必要的,至于显示访问还是隐式转换就要看具体想法了

//尽量不要对数组做typedef
typedef std::string mater[4];
std::string *pal=new mater;
delete[] pal;

//函数调用的参数顺序不确定
void mater(fa(),fb());
fa和fb的执行顺序是没有办法确定的

//copy structure是用于定义pass-by-value行为的

//对构造函数声明explicit会让编译器防止隐式转换
class A
{
public:
 explicit A(int i):mi(i){}
private:
 int mi;
}
当调用
A mm=1;
实际上是先调用A(1)生成一临时对象,再调用copy stru对此对象操作形成新对象,如果stru是explicit的A(1)就不会隐式调用
魔术啊

//当所有函数参数需要转换时用non-menber函数
因为对于this本身在menber函数里面无法作到转换
主要例子是operator *

//对于成员有指针的类在成员函数中加入swap何以减轻swp的负担

//转换类型
const_cast 常量性去掉
dynamic_cast 向子类转型
reinterpret_cast 低级转型,一般不可移植
static_cast 加上常量性,强迫隐式转换,基本都可用这个
dosome(static_cast<Mater>(15));若Mater构造函数为explicit也可以这样来调用其构造临时对象

//dynamic_cast尽量少用
if(MaterD *pm=dynamic_cast<MaterD *>(maters))...

//handle即操作句柄并没有其他意思

//在class声明中定义的函数都是inline的

//对virtual函数调用的inline函数将落空

//virtual意味着"等待,直到运行时才决定"

//用函数指针访问的inline函数通常不在被调用点inline

//如果有个异常在对象构造期间抛出,已构造的那部分将被销毁

//构造函数不要声明为inline

//记住一点当单当编译器看到定义式的时候一定知道定义的东西的大小

//当声明一个函数用道class时并不需要其定义(返回值也一样)
class Date;
Date mater();
void mater(Date mm);

//global作用域是最外部的,local是最内部的

//名称即名称,没有其他意思,确定变量或函数名都是名称

//在Dclass中覆盖了名称这时后如果只想覆盖一部分,可以用using Bclass::f,前提是public继承
class Bclass
{
public:
  void mf1();
  void mf1(int);
};
class Dcalss:public Bclass
{
public:
  using Bclass::mf1;
  void mf1();
};
现在的mf1()在Dclass中都可以调用了

//对于纯虚的函数,一般没有定义的,如果有定义并且要调用它
若draw()为Shape的一个纯虚函数,其调用方法为
Shape *ps=new Square;
ps->Shape::draw();

//std::tr1::function<int (const MaterFun&)>
这就可以最大限度的支持不同函数调用,支持隐式转换,兼容所有调用物
只要这个东西是可以接受MaterFun&的引用返回int就可以调用
float f1(MaterFun &kk);
std::tr1::function<int (const MaterFun&)> hhh(f1);
float可以对应int,MaterFun &对应const MaterFun&
更神奇的是
class MMH
{
public:
 int operator() (const MaterFun&);
}
std::tr1::function<int (const MaterFun&)> hhh(MMH());
这样都可以
再来一个更神奇的
class MMH
{
public:
 float hh(const MaterFun&);
}
MMH tmm;
std::tr1::function<int (const MaterFun&)> wokao(std::tr1::bind(&MMH::hh,tmm,_1));
对于std::tr1::bind(&MMH::hh,tmm,_1)的原因
因为MMH::hh实际上有两个参数(包括一个*this),把对象tmm绑定到函数hh上,即是说这个this用的是tmm

//non virsual函数调用随指针类型
任何情况下不应该重定义一个no visual 函数

//所谓静态类型即是声明是采用的类型,动态类型是目前对象所指的类型
不要重定义继承而来的缺省参数值
原因是缺省参数值是静态绑定在静态类型上面的
class Shape
{
  virtual void draw(int i=1)const=0;
};
class Circle
{
  virtual void draw(int i=2);
}
当调用
Shape *ps=new Circle;
ps->draw();
这里的draw()调的是Circle的,但是缺省参数却是Shape的(i=1)

//private继承意味"根据**物实现出"

//对于empty class c++会差一个char到空对象

//private继承只有在
需要调用bclass的protect变量
重定义bclass的virsual函数
EBO空白对象初始化(最大限度的节约空间)

//多继承调用歧义函数
mp.Mater::check();

//virtual base class
用于避免多继承的成员变量重复
class File{};
class InputFile:virtual public File{};
class OutputFile:virtual public File{};
class IOFile:public InputFile,public OutputFile{};
这里IOFile只维护一分File的成员变量
其实它的行为有点象java的interface,最好不要含成员变量(这样会加大系统负担)

//template支持接口是隐式(基于有效表达式),编译多态(基于template具现化和函数重载解析)

//嵌套从属类型
template<typename C> void mater(const C& mm)
{
  typename C::mmg mmd;
}
这里的C::mmg编译器默认是C的成员,但是加上typename以后编译器解释为一种类型了
typename作为嵌套从属类型标志只是不允许出现在base classes list 和 men init list,其它情况一定要用
template<class T> class D:public B<T>::N
{
public:
 D(int x):B<T>::N(x)
 {
  typename B<T>:N temp;
 }
}

//继承一个template class,子类不会在基类里面寻找继承来的名称
原因:base class template可能被特化
解决:
1.this->sendClear();加this
2.在调用前加using MSG<C>::sendClear;
3.MSG<C>::sendClear();但是这样会关闭virsual绑定行为

//用成员函数模板兼容所有类型(泛化copystruct)
template<class T>
class SmartPtr
{
public:
  template<class U>
  Smart(const SmartPtr<U>& other);
}

//在class tamplate中tmplate名称可以作为"template和其参数"的简约表达

//iterator_traits的建立
template <class T>
class deque
{
public:
  class iterator
  {
  public:
    typedef random_access_iterator_tag iterator_category;
   
    ...
  };
  ...
};
在traits里面加标示统一管理
template <class T>
struct iterator_traits
{
  typedef typename T::iterator_category iterator_category;
  ...
};
指针特化处理
template <class T>
struct iterator_traits<T*>
{
  typedef random_access_iterator_tag iterator_category;
  ...
};
使用用于判断iterator类型
if(typeid(typename std::iterator_traits<deque>::iterator_category)==typeid(std::random_access_iterator_tag))

//TMP模板元编程
在编译期实现阶乘
template<unsigned n>
struct Mater
{
 enum {value=n*Mater<n-1>::value};
};
template<>
struct Mater<0>
{
 enum {value=1};
};
在这里实质是具现化第归函数

//new-handler
当operator new无法执行成功的时候会调用的函数
void otmen()
{
  std::cerr<<"wokao nomen"<<std::endl;
  sttd::abort();
}
int main()
{
 std::set_new_handler(otmen);
  ...
}

//nothrow new
Widget *pw=new (std::nothrow)Widget;
if(pw==NULL)
 ...
不抛出异常的new
 
//每个placement new都对应一个placement delete

 

 

 

 

 

 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值