标签:effective c++ c++ 语法优化
Effective C++第四篇,扩展的有点多...
(四).设计与声明
____________________________________________________________________________________________________________________________________
条款24:若所有参数皆需类型转换,请为此采用non-member函数
#1.如果你需要为某个函数的所有参数(包括被 this指针所指的那个隐喻参数)进行//假设有个有理数类:
class Rational{
public:
    Rational(int numrator=0, int denomination=1);
    int numerator()const;
    int denomination()const;
    ...
};
//如果operator*写成Rational成员函数的话:
class Rational{
public:
    ...
    const Rational operator*(const Rational& rhs)const;
    ...
};
Rational oneEigth(1,8);  //很好
Rational oneHalf(1,2);   //很好
Rational result = oneHalf * oneEighth;  //很好
result = result * oneEighth //很好
//当尝试混合运算时:
result = oneHalf*2;   //result = oneHalf.operator*(2);很好
result = 2*oneHalf;   //result = 2.operator*(oneHalf);出错,继续尝试non-member函数
//当编译器试图调用non-member函数 result = operator*(2, oneHalf);时
//依旧没有找到对应的non-member函数,因此最终导致出错。
//【所以我们应该实现一个这样的non-member函数】:
const Rational operator*(const Rational& lhs,const Rational& rhs)
{
    return Rational(lhs.numerator()*rhs.numerator(),
                lhs.denomination()*rhs.denomination());
}namespace std{
    template<typename T>
    void swap(T&a, T&b)        //std:swap的典型实现
    {                           //置换a和b的值
        T temp(a);
        a = b;
        b = temp;
    }
}反之,如果因class或class template使用了pImp手法(pointer to implementation):class WidgetImpl{
public:
    ...
private:
    int a, b, c;
    std::vector<double> v;
    ...
};
class Widget{
public:
    Widget(const Widget& rhs);
    Widget& operator=(const Widget&rhs)
    {
        ...
        *pImv = *(rhs.pImpl);
        ...
    }
    ...
private:
    WidgetImpl* pImv;
};从而引起了效率不足,请做以下几件事来提高效率://pImv是private成员变量,所以要从内部来swap,
//当然也可用friend,但这样的写法和STL一致
class Widget{
public:
    ...
    void swap(Widget& other)
    {
        using std::swap;
        swap(pImpl, other.pImpl);
    }
    ...
};
//该swap函数保证了异常安全性和高效性,因为swap置换的是指针,对于指针
//和内置类型的置换操作绝不会抛出异常,并且还很高效。如果是对自定义类型
//执行swap函数,则会因为copy构造函数和copy assignment操作符而允许抛出异常。namespace WidgetStuff{
    ...
    template<typename T>
    class Widget {...}
    ...
    template<typename T>
    void swap(Widget<T>& a, Widget<T>& b)
    {
        a.swap(b);
    }
}namespace std{
    template<>
    void swap<Widget>(Widget& a, Widget& b)
    {
        a.swap(b);
    }
}
//=======================================================================
// 理由:
// 好处是即使客户不慎直接调用了std::swap,至少也能获得一个全特化版的swap函数,
// 另外,C++只运行class template偏特化,但不允许function template的偏特化,
// 因此无法通过编译(虽然某些编译器错误的接受了它)。
//=======================================================================(五).实现
____________________________________________________________________________________________________________________________________
std::string encryptPassword(const std::string& password)
{
    using namespace std;
    string encrypted;
    if(password.length() < MinimumPasswordLength)
        throw logic_error("Password is too short");
    ...
    
    return encrypted;
}
//若抛出logic_error异常,encrypted完全未被使用。
//所以应改为:
std::string encryptPassword(const std::string& password)
{
    
    if(password.length() < MinimumPasswordLength)
        throw logic_error("Password is too short");
    using namespace std;
    string encrypted(password);
    ...
    return encrypted;
}//方法A:定义于循环外
Widget w;
for(int i=0;i<n;i++){
    w = 取决于i的某个值;
    ...
}
//方法B:定义于循环外
for(int i=0;i<n;i++){
    Widget w(取决于i的某个值);
}
//做法A:1个构造函数+1个析构函数+n个赋值操作
//做法B:n个构造函数+n个析构函数____________________________________________________________________________________________________________________________________身上执行不安全,荒谬的操作,请尽量避免转型。
理由2:任何一个类型转换往往令编译器编译出运行期间执行的码,例如:
class Base{...};
class Derived:public Base{...};
Derived d;
Base* pb = &d;
//为获取Base*指针值,在运行期间会有个偏移量(offset)添加在Derived*指针身上,
//编译器会为此额外编译出运行期间执行的码。(注意:这里的offset并不明确,
//因为对象的布局方式和地址计算方式随编译器的不同而不同。)//假设先Window/SpecialWindow继承体系中只有SpecialWindows才支持闪烁效果,
//试着不要这样做:
class Window {...};
class SpecialWindow:public Window{
public:
    void blink();
    ...
};
typedef std::vector<std::tr1::shared_ptr<Window>> VPW;
VPW winPtrs;
...
for(VPW::iterator iter = winPtrs.begin();
    iter != winPtrs.end();++iter){
    if(Specialwindow* psw=dynamic_cast<SpecialWindow*>(iter->get()))
        psw->blink();
}
//应该改成这样:
typedef std::vector<std::tr1::shared_ptr<SpecialWindow>> VPW;
VPW winPtrs;
...
for(VPW::iterator iter = winPtrs.begin();
    iter != winPtrs.end();++iter){
    (*iter)->blink();
}(2).多重继承中,用virtual函数代替dynamic_cast所做的事//用dynamic_cast时如下所示:
class Window {...};
...
typedef std::vector<std::tr1::shared_ptr<Window>> VPW;
VPW winPtrs;
...
for(VPW::iterator iter = winPtrs.begin();
    iter != winPtrs.end();++iter){
    if(SpecialWindow* psw1=
        dynamic_cast<SpecialWindow*>(iter->get()))psw1>blink();
    else if(SpecialWindow* psw2=
        dynamic_cast<SpecialWindow*>(iter->get()))psw2->blink();
    else if(SpecialWindow* psw3=
        dynamic_cast<SpecialWindow*>(iter->get()))psw3->blink();
}
//以上的做法中有一连串dynamic_cast,这会使产生出来的代码又长又慢,
//而且基础不稳,因为继承体系一有改变,所有这一类代码都要检查看看
//是否需要修改,例如添加一个新的derived class,则要在一连串判断
//中加入新的条件分支,及其不易维护。
//所以应该改成这样:
class Window {
public:
    virtual void blink();{}   //缺省实现码什么也没做
    ...
};
class SpecialWindow:public Window{
public:
    virtual void blink(){...}; //blink做某些事
    ...
};
...
typedef std::vector<std::tr1::shared_ptr<Window>> VPW;
VPW winPtrs;
...          //容器,内含Window指针,指向所有可能的派生类对象
for(VPW::iterator iter = winPtrs.begin();
    iter != winPtrs.end();++iter){
    (*iter)->blink();
}
#3.如果转型无可避免,请将它隐藏在函数背后,这样客户调用该函数时,不需要将
转型动作放入它们的代码里,保证了代码的封装性和易维护性。class Point{
public:
    Point(int x, int y);
    ...
    void setX(int newVal);
    void setY(int newVal);
    ...
};
struct RectData{
    Point ulhc;
    Point lrhc;
};
class Rectangle{
    ...
private:
    std::tr1::shared_ptr<RectData> pData;
    Point& upperLeft()const{return pData->ulhc;}
    Point& lowerRight()const{return pData->lrhc;}
    ...
};
Point coord1(0,0);Point coord2(100, 100);
const Rectangle rec(coord1, coord2);
rec.upperLeft().setX(50);
//这里返回的handles可以改变,但与upperLeft const()成员函数的本意是相反的。
//所以应改成:
class Rectangle{
    ...
private:
    ...
    const Point& upperLeft()const{return pData->ulhc;}
    const Point& lowerRight()const{return pData->lrhc;}
    ...
};
//这样就可以在保证读写权的同时禁止涂写权。//当upperLeft(),lowerRight()为non-const时:
class Rectangle{
    ...
private:
    ...
    Point& upperLeft(){return pData->ulhc;}
    Point& lowerRight(){return pData->lrhc;}
    ...
};
Point coord1(0,0);Point coord2(100, 100);
Rectangle rec(coord1, coord2);
//我们可以如下这样用函数统一接口设置值和得到值:
rec.upperLeft().setX(50);
int val = rec.lowerRight().getY();____________________________________________________________________________________________________________________________________//一个用copy-and-swap的示例:
struct PMImpl{            //PMImpl = PrettyMenu Impl
    std::tr1::shared_ptr<Image> bgImage;
    int imageChanges;
};
class PrettyMenu{
    ...
private:
    Mutex mutex;
    std::tr1::shared_ptr<PMImpl> pIml;
};
void PrettyMenu::changeBack(std::istream& imgSrc)
{
    using std::swap;
    Lock ml(&mutex);        //获得mutex的副本数据
    std::tr1::shared_ptr<PMImpl> pNew(new PMImpl(*pImpl));
    pNew->bgImage.reset(new Image(imgSrc)); //修改副本
    ++pNew->ImageChanges;
    swap(Impl, pNew);        //置换(swap)数据,释放mutex
}
//,但”强烈保证“ 并非对所有函数都具有可实现或具备实现意义:(1).因为如copy-and-swap这样的强烈保证往往会耗费更多的时间和空间,为了void someFunc{
    ...     //对local状态做一份副本
    f1();
    f2();
    ...     //将修改后的状态置换过来
}
//假设someFunc对“局部数据”提供强烈保证,但f1(),f2()对someFunc()来说是
//非局部性的”,因此f1(),f2()会对someFunc()的强烈保证期望造成影响,
//假设f1(),f2()提供一个基本保证,显然someFunc将只会提供基本保证,
//而若f1(),f2()也提供强烈保证,但若f1(),f2()并未抛出异常,在此之后
//却抛出了异常,那么someFunc()也无法提供强烈保证,毕竟程序状态改变了。
//另一方面,在someFunc中像某些数据库之类的非局部数据一旦被改变,想恢复
//就很困难,这时someFunc想提供强烈保证就真的很难了。中的最弱者(从上述例子中可以看出)。
____________________________________________________________________________________________________________________________________
标签:effective c++ c++ 语法优化
原文地址:http://blog.csdn.net/beyond_ray/article/details/43735815