《Effective C++》

再讀高效c++厕鹃,頗有收獲兢仰,現(xiàn)將高效c++中的經(jīng)典分享如下,希望對(duì)你有所幫助剂碴。

奉上很火的 你的名字圖系列

1把将、盡量以const \enum\inline 替換#define

(1)對(duì)于單純常量,最好以const\enum替換#define
    #define ASPECT_RATIO 1.653 //大量引用會(huì)帶來(lái)代碼體積膨脹
    const double aspectratio=1.653;

    const char * const p = "hello world";//定義一個(gè)常量的不變的字符串
    const string p("hello world");//在c++中換string 是更好的 
    //////////////////////////////////////////////////////////////////////
 class Base
{
  private:
         static const int NumTurns;//為了確保此常量?jī)H有一份用static忆矛、 為了將常量的作用范圍限制于class內(nèi)
         int scores[NumTurns];
};
const int Base::NumTurns = 5;//定義式

 class Base
 {
    private:
        enum {NumTurns = 5};//防止別人獲得一個(gè)指針或者引用指向你的整數(shù)常量
        int scores[NumTurns];
 }; 
(2)對(duì)于形式函數(shù)的宏察蹲,最好改用inline函數(shù)替換
  #define MAX(a,b) ((a)>(b) ? (a):(b))//用宏實(shí)現(xiàn)函數(shù)導(dǎo)致不必要的運(yùn)算,以inline替換
 void main()
{
   int a = 5,b = 0;
  cout<<MAX(++a,b)<<endl;//結(jié)果是7
  cout<<MAX(++a,b+10)<<endl;//結(jié)果是10
  cout<<a<<endl;//結(jié)果是8
}

template<typename T>
inline T Max(const T &a,const T &b)
 {
    return a>b ? a:b;
  }
void main()
{
  int a = 5,b = 0;
  cout<<Max(++a,b)<<endl;//結(jié)果是6
  cout<<Max(++a,b+10)<<endl;//結(jié)果是10
  cout<<a<<endl;//結(jié)果是7
}

拓展:

 template<typename T>//inline一般被置于頭文件內(nèi)催训,因?yàn)槭窃诰幾g階段完成
 inline const T& max(const T& a,const T& b)//構(gòu)造和析構(gòu)往往是Inline的糟糕人選
 {
    return a < b ? b : a;
 }


inline void PrinOrd(BNode *p)//內(nèi)聯(lián)inline只是一種建議,底層編譯器不一定會(huì)給你內(nèi)聯(lián),比如 遞歸洽议、多層for循環(huán),編譯器會(huì)自動(dòng)將inline忽略掉
{
    if(NULL != p)
    {
        PrinOrd(p->left);
        cout<<p->val<<" ";
        PrinOrd(p->right);
    }
}

2、盡可能使用const

(1)可以將函數(shù)參數(shù)漫拭、函數(shù)返回類(lèi)型聲明為const,是為了防止修改
class Rational{};
const Rational operator*(const Rational &lhs,const Rational &rhs)//返回值和參數(shù)均設(shè)為const是為了避免if(a*b = c)的錯(cuò)誤以及惡意修改參數(shù)的錯(cuò)誤
{
    return lhs * rhs;
}
void main()
{
    vector<int> vec;
    const vector<int>::iterator iter = vec.begin();//相當(dāng)于T* const
    *iter = 10;
    ++iter;//error

    vector<int>::const_iterator citer = vec.begin();//相當(dāng)于T const*
    *citer = 10;//error
    ++citer;
}

3亚兄、了解c++默默編寫(xiě)并調(diào)用哪些函數(shù)

class TextBlock
{
  public:
TextBlock(char* str):text(str){;}//調(diào)用string::string(const char *);構(gòu)造函數(shù)
const char& operator[](size_t index) const
{
    cout << "const" << endl;
    return text[index];
}
char &operator[](size_t index)//返回引用是為了可以改變返回的值,若返回值采驻,是通過(guò)eax寄存器帶回返回值审胚,是不可以改變返回值的
{
    cout << "non-const" << endl;
    return text[index];
}
void Show(size_t index)//每一個(gè)成員函數(shù)的默認(rèn)第一個(gè)參數(shù)為this指針匈勋,如TextBlock *const this
{
    cout<<text[index]<<endl;////////call string []
    //cout<<(*this)[index]<<endl;/////call TextBlock []
}
ostream &operator<<(ostream &out)const//add const==>const TextBlock *const this
{
    out<<text;
    return out;
}
  private:
      string text;
};
ostream &operator<<(ostream &out,const TextBlock& rhs)
{
    rhs<<out;
    return out;
}
void main()
{
    //const char *p = string("hello world");//error
    //const char *p = string("hello world").c_str();//return const char *

    TextBlock tb("hello cc");
    tb.Show(0);/////////Show(&tb,0);//然后 這個(gè)&tb(實(shí)參)傳給了一個(gè)形參this , static成員函數(shù)膳叨、構(gòu)造函數(shù)洽洁、友元函數(shù)沒(méi)有this指針
    cout << tb[0] << endl;
    const TextBlock tb2("hello cc");
      cout << tb2[0] << endl;

    TextBlock str("hello cc23");
    char *p = &str[0];
    *p = 'j';
    cout<<str<<endl;
}

4、成員函數(shù)后加const菲嘴,還可以通過(guò)在成員變量前加mutable關(guān)鍵字和強(qiáng)轉(zhuǎn)來(lái)達(dá)到改變成員變量的目的

class CTextBlock
{
public:
    size_t length() const;
    size_t length();
private:
    char *pText;
    mutable size_t textlength;//加mutable關(guān)鍵字可以使得后加const的成員函數(shù)可以改變類(lèi)內(nèi)的成員變量
    mutable bool lengthIsValid;
};
//再?gòu)?qiáng)調(diào)一次,成員函數(shù)內(nèi)部后加const和不加const的區(qū)別
//CTextBlock  nonconst: this 類(lèi)型 CTextBlock* cnost this
//CTextBlock  const   : this 類(lèi)型 const CTextBlock* const this                
size_t CTextBlock::length() const
{
    if(!lengthIsValid)
    {
        textlength = strlen(pText);
        lengthIsValid = true;
    }
    return textlength;
}

5诡挂、解決代碼重復(fù)的方法

  class Base
{
  public:
      const char& operator[](size_t index) const
      {
        //執(zhí)行邊界檢查、志記數(shù)據(jù)訪問(wèn)临谱、檢驗(yàn)數(shù)據(jù)訪問(wèn)性
        return text[index];
    }
    char& operator[](size_t index) //在non-const中調(diào)用const函數(shù)
{
    //執(zhí)行邊界檢查璃俗、志記數(shù)據(jù)訪問(wèn)、檢驗(yàn)數(shù)據(jù)訪問(wèn)性
    //return text[index];
    //return (char&)((const Base*)this)->operator[](index);//c語(yǔ)言
    return const_cast<char&>(static_cast<const Base&>(*this)[index]);//為了防止代碼重復(fù)度大
}
private:
    string text;
};

6悉默、初始化的兩種方式pk——成員初值列和賦值初始化

  class PhoneNumber{};
  class ABEntry
{
  public:
ABEntry(const string& name,const string& address,const list<PhoneNumber>& phones)
    :thename(name),theaddress(address),thephones(phones),numTimes(0){}//thename以name為初值調(diào)用拷貝構(gòu)造函數(shù)
//調(diào)用成員初值列進(jìn)行初始化城豁,對(duì)于內(nèi)置類(lèi)型來(lái)說(shuō),效率高抄课。
//以其聲明的次序被初始化
private:
    string thename;
    string theaddress;
    list<PhoneNumber> thephones;
    int numTimes;
};
ABEntry(const string& name,const string& address,const list<PhoneNumber>& phones)//調(diào)用賦值初始化成員變量唱星,效率低
{
    thename = name;
    theaddress = address;
    thephones = phones;
    numTimes = 0;
}

7、c++構(gòu)造賦值時(shí)調(diào)用的函數(shù)

  class Empty
{
public:
    Empty(){}
    ~Empty(){}
    Empty(const Empty& rhs){}//對(duì)象未被聲明時(shí)使用
    Empty& operator=(const Empty& rhs){}//對(duì)象被聲明后使用
};
void main()
{
    Empty e1;//構(gòu)造函數(shù)
    Empty e2(e1);//拷貝構(gòu)造
    e2 = e1;//賦值運(yùn)算符的重載函數(shù)
}

8跟磨、阻止復(fù)制獨(dú)一無(wú)二的東西

class Uncopyable
{
protected:
    Uncopyable(){}
    ~Uncopyable(){}
private://將拷貝構(gòu)造和賦值運(yùn)算符聲明為private
    Uncopyable(const Uncopyable&);
    Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale:private Uncopyable{};//通過(guò)繼承Uncopyable類(lèi)间聊,阻止復(fù)制獨(dú)一無(wú)二的東西

9蜗搔、異常的相關(guān)操作

  class DBconnection
{
  public:
    static DBconnection create();
    void close();
};
  class DBcon//管理DBconnection對(duì)象1
{
  public:
    ~DBcon()//處理異常
{
    try{db.close();}//調(diào)用abort()處理
    catch(){
        abort();
    }

    try{db.close();}//吞下異常
    catch(){
        ;
    }
}
private:
    DBconnection db;
};

class DBcon//管理DBconnection對(duì)象2
{
public:
    void close()//將某個(gè)操作函數(shù)運(yùn)行期間拋出的異常交到客戶(hù)手上
    {
      db.close();
        closed = true;
    }
    ~DBcon()//處理異常
    {
        if(!closed)
        {
          try{db.close();}
          catch(){
            ;
          }
      }
  }
private:
    DBconnection db;
    bool closed;
};

10谆奥、抽象類(lèi)——帶有純虛函數(shù)的類(lèi)

class AWOV//抽象類(lèi),供繼承使用
{
public:
virtual ~AWOV() = 0;//純虛函數(shù)
};
AWOV::~AWOV(){}//為析構(gòu)函數(shù)提供一份定義

11、不要在構(gòu)造和析構(gòu)期間調(diào)用virtual函數(shù)

class Transaction
{
public:
explict Transaction(const string& logInfo);
void logTransaction(const string& logInfo) const;
};
Transaction::Transaction(const string& logInfo)//不要在構(gòu)造和析構(gòu)期間調(diào)用virtual函數(shù)
{
logTransaction(logInfo);
}

class BuyTransaction:public Transaction
{
public:
BuyTransaction(parameters):Transaction(createLogString(parameters))//派生類(lèi)構(gòu)造函數(shù)
{
;
}
private:
//目標(biāo):如何利用派生類(lèi)的方法來(lái)給基類(lèi)構(gòu)造對(duì)象违施?存在以下三種思路
//1.使用虛函數(shù)僵蛛?
//2.使用派生類(lèi)成員函數(shù)尚蝌?
//3.使用派生類(lèi)的靜態(tài)函數(shù)
//顯然,思路1和2都是依賴(lài)于this指針,而構(gòu)造函數(shù)中可以認(rèn)為對(duì)象正在構(gòu)造充尉,屬于半成品飘言,絕對(duì)不允許泄露this指針出去
//所以 應(yīng)該使用思路3
static string createLogString(parameters);//這里放在私有,是為了防止用戶(hù)在外部亂調(diào)用
};

12驼侠、令賦值運(yùn)算符函數(shù)返回左值的引用

class Bitmap{};
class Widget//一個(gè)協(xié)議姿鸿,為了實(shí)現(xiàn)連鎖賦值
{
public:
Widget& operator=(const Widget& rhs)//版本一
{
if(this==&rhs)return this;//證同測(cè)試,如果是自我賦值倒源,就不做任何事情
delete pb;
pb=new Bitmap(
rhs.pb);
return this;//返回左值的引用
}
Widget& operator=(const Widget& rhs)//版本二苛预,解決版本一new調(diào)用或Bitmap構(gòu)造函數(shù)出現(xiàn)異常
{
if(this==&rhs)return this;//證同測(cè)試,如果是自我賦值相速,就不做任何事情
Bitmap
pOrig=pb;
pb=new Bitmap(
rhs.pb);
delete pOrig;
return this;//返回左值的引用
}
void Swap(Widget& rhs);//交換
this和rhs的數(shù)據(jù)
Widget& operator=(const Widget& rhs)//版本三
{
if(this==&rhs)return *this;//證同測(cè)試碟渺,如果是自我賦值,就不做任何事情
Widget temp(rhs);
Swap(temp);
return *this;
}
Widget& operator=(Widget rhs)//版本四突诬,提高效率
{
if(this==&rhs)return *this;//證同測(cè)試苫拍,如果是自我賦值,就不做任何事情
Swap(rhs);
return *this;
}
Widget& operator+=(const Widget& rhs)
{
return *this;//返回左值的引用
}
Widget& operator=(int rhs)
{
return this;//返回左值的引用
}
private:
Bitmap
pb;
};

13旺隙、記住對(duì)對(duì)象內(nèi)的所有成員變量及基類(lèi)部分確保復(fù)制

void logcall(const string& funcName);//記住對(duì)對(duì)象內(nèi)的所有成員變量及基類(lèi)部分確保復(fù)制
class Date{};
class Customer
{
public:
Customer(const Customer& rhs);
Customer& operator=(const Customer& rhs);
private:
string name;
Date lastTransaction;//
};
Customer::Customer(const Customer& rhs):name(rhs.name)
{
logcall("hello cc1");
}
Customer& Customer::operator=(const Customer& rhs)
{
if(this==&rhs) return *this;
logcall("hello cc2");
name = rhs.name;
return *this;
}
class PriorityCustomer:public Customer
{
public:
PriorityCustomer(const PriorityCustomer& rhs);
PriorityCustomer& operator=(const PriorityCustomer& rhs);
private:
int priority;
};
PriorityCustomer::PriorityCustomer(const PriorityCustomer& rhs):Customer(rhs),priority(rhs.priority)
{
logcall("hello cc1");
}
PriorityCustomer& PriorityCustomer::operator=(const PriorityCustomer& rhs)
{
if(this==&rhs) return *this;
logcall("hello cc2");
Customer::operator=(rhs);
priority=rhs.priority;
return *this;
}

14绒极、管理資源之智能指針

(1)、三種方式解決資源泄露
class Investment{};
Investment* createInvestment();
void f()//版本一,有缺陷
{
Investment* pInv=createInvestment();
//中間執(zhí)行return或者拋出異常導(dǎo)致無(wú)法執(zhí)行delete蔬捷,造成資源泄露
delete pInv;
}
void f()//版本二,解決版本一的資源泄露
{
auto_ptr<Investment> pInv(createInvestment());//智能指針垄提,獲得資源后立刻放進(jìn)管理對(duì)象內(nèi),管理對(duì)象運(yùn)用析構(gòu)函數(shù)確保資源釋放
//auto_ptr在復(fù)制或者賦值后之前的值變?yōu)镹ULL
}
void f()//版本三周拐,解決版本二的復(fù)制賦值錯(cuò)誤
{
shared_ptr<Investment> pInv(createInvestment());
}//兩個(gè)智能指針在其析構(gòu)函數(shù)中做delete而不是delete[]動(dòng)作铡俐,是因?yàn)関ector和string總是可以取代動(dòng)態(tài)分配而得到的數(shù)組
(2)、防止死鎖
void lock(Mutex* pm);//鎖定pm所指的互斥器
void unlock(Mutex* pm);//將互斥器解除鎖定
class Lock:private Uncopyable//版本一妥粟,禁止復(fù)制
{
public:
explicit Lock(Mutex* pm):mutexPtr(pm)
{
lock(mutexPtr);
}
~Lock()
{
unlock(mutexPtr);
}
private:
Mutex *mutexPtr;
};

class Lock//版本二审丘,對(duì)底層資源運(yùn)用引用計(jì)數(shù)法
{
public:
explict Lock(Mutex* pm):mutexPtr(pm,unlock)
{
lock(mutexPtr.get());//auto_ptr和shared_ptr都提供一個(gè)get成員函數(shù),用來(lái)執(zhí)行顯示轉(zhuǎn)換勾给,返回智能指針內(nèi)部的原始指針
}
~Lock()
{
unlock(mutexPtr);
}
private:
shared_ptr<Mutex> mutexPtr;
};
(3)shared_ptr和auto_ptr
class Investment
{
public:
bool isTaxfree() const;
};
Investment* createInvestment();
shared_ptr<Investment> pi1(createInvestment());
bool taxable1=!(pi1->isTaxfree());//將pi1隱式轉(zhuǎn)換為底部原始指針滩报,并調(diào)用operator->取值
auto_ptr<Investment> pi2(createInvestment());
bool taxable2=!((pi2).isTaxfree());//將pi2隱式轉(zhuǎn)換為底部原始指針,并調(diào)用operator取值
(4)隱式轉(zhuǎn)換和顯示轉(zhuǎn)換函數(shù)
Derived getbase();
void releasebase(Derived a);
class base
{
public:
explicit base(Derived a):text(a){}
~base()
{
releasebase(a);
}
Derived get() const{return text;}//顯示轉(zhuǎn)換函數(shù)
operator Derived() const{return text;}//隱式轉(zhuǎn)換函數(shù)

private:
Derived text;
};

(5)以獨(dú)立語(yǔ)句將newed對(duì)象置入智能指針
int priority();
void processWidget(shared_ptr<Widget> pw,int priority);
void main()
{
processWidget(new Widget,priority());//無(wú)法通過(guò)編譯
processWidget(shared_ptr<Widget>(new Widget),priority());//可以通過(guò)編譯播急,但執(zhí)行期間可能造成內(nèi)存泄漏
shared_ptr<Widget> pw(new Widget);//以獨(dú)立語(yǔ)句將newed對(duì)象置入智能指針#include <memory>//智能指針頭文件
processWidget(pw,priority());
}

15脓钾、以傳引用代替?zhèn)髦?/h3>

(1)明顯的傳值pk傳引用
class Base{};
class Derived{};
shared_ptr<Base> createbase()
{
return shared_ptr<Base>(new Derived);//解決了cross-Dll problem,shared_ptr會(huì)自動(dòng)使用每一個(gè)指針專(zhuān)屬的刪除器桩警。
}
////////////////////////////////////////////////
class Person
{
public:
Person();
virtual ~Person();//為基類(lèi)聲明虛析構(gòu)函數(shù)
private:
string name;
string address;
};
class student:public Person
{
public:
student();
~student();
private:
string schoolname;
string schooladdress;
};
bool validateStudent(Student s);//需要多次調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)可训,效率低
bool validateStudent(const Student& s);//效率高
void main()
{
Student platu;
bool platuisok = validateStudent(platu);
}
(2)傳引用來(lái)解決類(lèi)型切割
class Window
{
public:
string name() const;
virtual void display() const;
};
class WindowWithScrollbars:public Window
{
public:
virtual void display() const;
};
void PrintnameAndDisplay(Window w)//解決類(lèi)型切割,將Window w改為const Window& w
{
cout<<w.name()<<endl;
w.display();
}
void main()
{
WindowWithScrollbars wsb;
PrintnameAndDisplay(wsb);//此處有類(lèi)型切割
}
拓展:
//一般STL的迭代器和函數(shù)對(duì)象以及內(nèi)置類(lèi)型都用傳值
class Fun
{
public:
void operator()(int x)
{
cout<<x<<endl;
}
};
void main()
{
Fun x;//這就是函數(shù)對(duì)象
x(123);
}

16捶枢、寧可以non-member沉噩、non-friend函數(shù),替換member函數(shù)

class Rational
{
public:
Rational(int numerator=0,int denomerator=1);
private:
int n,d;
friend const Rational operator* (const Rational& lhs,const Rational& rhs);
};
inline const Rational operator* (const Rational& lhs,const Rational& rhs)//定義為non-member函數(shù)是為了支持函數(shù)的所有參數(shù)進(jìn)行隱式類(lèi)型轉(zhuǎn)換,支持混合運(yùn)算
{
return Rational(lhs.nrhs.n,lhs.drhs.d);//不要返回局部變量(在棧上或者堆上)的引用柱蟀,也不要返回局部靜態(tài)變量的引用
}
//將成員變量聲明為private可以增加其封裝性川蒙。
//namespace可以跨越多個(gè)源碼文件而class不可以。

17长已、盡可能延后變量定義式的出現(xiàn)時(shí)間

string::encryptPassword(const string& password)
{
//string encrypted;
if(paassword.length() < mininumPasswordlength)
{
throw logic_error("password is too short");
}
string encrypted;//延后它的實(shí)現(xiàn)畜眨,避免構(gòu)造和析構(gòu)成本

return encrypted;

}

18、c++的四種轉(zhuǎn)型

const_cast<T>(expression)//將對(duì)象的常量性移除
dynamic_cast<T>(expression)//(安全向下轉(zhuǎn)型)术瓮,用來(lái)決定某對(duì)象是否歸屬繼承體系中的某一個(gè)類(lèi)型//避免使用
reinterpret_cast<T>(expression)//低級(jí)轉(zhuǎn)型康聂,不可移植
static_cast<T>(expression)//強(qiáng)迫隱式轉(zhuǎn)換

class Window//盡量少做轉(zhuǎn)型動(dòng)作
{
public:
virtual void onResize(){}
};
class SpecialWindow:public Window
{
public:
virtual void onResize()
{
//static_cast<Window>(this).onResize();//這是在當(dāng)前對(duì)象的base_class成分的副本上調(diào)用Window::onresize(),然后再當(dāng)前對(duì)象身上執(zhí)行SpecialWindow專(zhuān)屬動(dòng)作
Window::onResize();
}
void bink();
};
typedef vector<shared_ptr<SpecialWindow>> VPSW;
VPSW winPtrs;
for(VPSW::iterator iter = winPtrs.begin(); iter!=winPtrs.end();++iter)
{
(
iter)->bink();
}
//避免返回handles(包括references,指針,迭代器)指向?qū)ο髢?nèi)部胞四,除了operator[]

19恬汁、為異常安全而努力是值得的

//=============================版本一===============================
class PrettyMenu
{
public:
void changeBackground(istream& imgSrc);
private:
Mutex mutex;
shared_ptr<Image> bgImage;
int imageChanges;
};
void PrettyMenu::changeBackground(istream& imgSrc)
{
Lock m1(&mutex);//獲得互斥器并確保它稍后被釋放
//delete bgImage;
//++imageChanges;
//bgImage = new Image(imgSrc);
bgImage.reset(new Image(imgSrc));//reset函數(shù)只有在new Image(imgSrc)被成功生成后才調(diào)用,delete在reset中被調(diào)用
++imageChanges;
}
//======================版本二=======cpoy and swap策略“修改對(duì)象的副本”====
struct PMImpl
{
shared_ptr<Image> bgImage;
int imageChanges;
};
class PrettyMenu
{
public:
void changeBackground(istream& imgSrc);
private:
Mutex mutex;
shared_ptr<PMImpl> PImpl;
};
void PrettyMenu::changeBackground(istream& imgSrc)
{
using std::swap;
Lock m1(&mutex);
shared_ptr<PMImpl> pnew(new PMImpl(*PImpl))
pnew->bgImage.reset(new Image(imgSrc));
++pnew->imageChanges;
swap(PImpl,pnew);
}

20辜伟、將文件之間的編譯依存關(guān)系降至最低

//使得編譯依存最小化的一般構(gòu)想是氓侧,相依與聲明式脊另,不要相依與定義式,基于此構(gòu)想约巷,有以下
//++=++++++++++++++++++++++++++Handle classes++++++++++++++++++++
//需要兩個(gè)頭文件偎痛,一個(gè)用于聲明式,一個(gè)用于定義式
class PersonImpl;//Person的實(shí)現(xiàn)類(lèi)
class Date;
class Address;
class Person
{
public:
Person(const string& name,const Date& birthday,const Address& addr)
:pImpl(new PersonImpl(name,birthday,addr))
{
;
}
string name() const
{
return pImpl->name();
}
string birthdate() const;
string address() const;
private:
shared_ptr<PersonImpl> pImpl;
};

//++=++++++++++++++++++++++++++Interface classes++++++++++++++++++
class Person//抽象類(lèi)独郎,不可以具現(xiàn)化踩麦,必須通過(guò)指針或者引用來(lái)撰寫(xiě)程序
{
public:
virtual ~Person();
virtual string name() const = 0;
virtual string birthdate() const = 0;
virtual string address() const = 0;
static shared_ptr<Person> Create(const string& name,const Date& birthday,const Address& addr);//工廠函數(shù),返回動(dòng)態(tài)分配所得到的指針
};
class RealPerson:public Person
{
public:
RealPerson(const string& name,const Date& birthday,const Address& addr)
:thename(name),theBirthdate(birthday),theaddress(addr)
{}
virtual ~RealPerson();
string name() const;
string birthdate() const;
string address() const;
private:
string thename;
Date theBirthdate;
Address theaddress;
};
shared_ptr<Person> Person::Create(const string& name,const Date& birthday,const Address& addr)
{
return shared_ptr<Person>(new RealPerson(name,birthday,addr));//會(huì)創(chuàng)建不同的derived class對(duì)象
}
void main()
{
string name;
Date dateofBirth;
Address address;
shared_ptr<Person> pp(Person::Create(name,dateofBirth,address));
cout<<pp->name<<"was born on"<<pp->birthdate()<<"and now lives at"<<pp->address();
}

21氓癌、繼承重載函數(shù)會(huì)被遮掩掉

class Base
{
public:
virtual void mf1() = 0;
virtual void mf1(int a)
{
x=a;
cout<<"mf1:"<<x<<endl;
}
virtual void mf2(int a)
{
x=a;
cout<<"mf2:"<<x<<endl;
}
void mf3(int a)
{
x=a;
cout<<"mf3:"<<x<<endl;
}
void mf4(double a)
{
x=a;
cout<<"mf3:"<<x<<endl;
}
private:
int x;
};
class Derived:public Base//繼承重載函數(shù)會(huì)被遮掩掉
{
public:
///一////////
using Base::mf1;

///二////////
virtual void mf1()
{
    ;
    //Base::mf1();//并不想繼承基類(lèi)多個(gè)版本函數(shù)
}

};
void main()
{
Derived d;
d.mf1();
d.mf1(5);
d.mf3(9.0);
}

22谓谦、區(qū)分接口繼承和實(shí)現(xiàn)繼承

class shape
{
public:
virtual void draw()=0;//讓繼承類(lèi)只繼承接口
virtual void error(const string& name);//讓繼承類(lèi)繼承接口和缺省實(shí)現(xiàn)
int objectid() const;//讓繼承類(lèi)繼承接口和一份強(qiáng)制性實(shí)現(xiàn)
};
class Rectangle:public shape
{};

23、函數(shù)指針舉例

class Person;
class Health
{
public:
typedef int (Hander)( Person&);
Health(Hander f):mfun(f){;}
int operator()(Person& src){return mfun(src);}
void Change(Hander f ){mfun = f;}
private:
Hander mfun;
};
int default_fun(Person& x)
{
return 10000;
}
int fun1(Person& x)
{
return 100;
}
class Person:public Health
{
public:
Person(int x,Hander f = default_fun):data(x),Health(f){;}
void ShowHealth()
{
cout<<Health::operator ()(
this)<<endl;
}
void Change(Hander f = default_fun){Health::Change(f);}
private:
int data;
};
void main()
{
Person a(1);
a.ShowHealth();//10000
a.Change(fun1);//會(huì)覆蓋掉Person中change成員函數(shù)的參數(shù)默認(rèn)值
a.ShowHealth();
}

24贪婉、考慮virtual函數(shù)以外的其它選擇

(1)反粥、template method模式
class Gamecharacter
{
public:
int HealthValue() const//NVI手法,優(yōu)點(diǎn)是可以在調(diào)用一個(gè)virtual函數(shù)之前設(shè)定好一些場(chǎng)景
{
int retval = doHealthValue();
return retval;
}
private:
virtual int doHealthValue() const
{
}
};
(2)谓松、Strategy模式
///////////////////一星压、基于Function Pointers的Strategy模式/////////////////////////
class Gamecharacter;
int defaultHealthCalc(const Gamecharacter& gc);
class Gamecharacter
{
public:
typedef int (HealthCalcFunc)(const Gamecharacter& gc);
explicit Gamecharacter(HealthCalcFunc hcf=defaultHealthCalc)
:HealthFunc(hcf)
{
;
}
int healthValue() const
{
return HealthFunc(
this);
}
private:
HealthCalcFunc HealthFunc;
};

///////////////////二、基于tr1::Function的Strategy模式/////////////////////////
class Gamecharacter;
int defaultHealthCalc(const Gamecharacter& gc);
class Gamecharacter
{
public:
typedef tr1::function<int (const Gamecharacter&)> HealthCalcFunc;
//函數(shù)接收一個(gè)引用指向const Gamecharacter鬼譬,并返回int娜膘。這個(gè)tr1::function類(lèi)型產(chǎn)生的對(duì)象可以持有任何與此簽名式兼容的可調(diào)用物,
//也就是說(shuō)這個(gè)可調(diào)用物的參數(shù)可以被隱式轉(zhuǎn)換為const Gamecharacter,而且其返回類(lèi)型可以被隱式轉(zhuǎn)換為int
explicit Gamecharacter(HealthCalcFunc hcf=defaultHealthCalc)
:HealthFunc(hcf)
{
;
}
int healthValue() const
{
return HealthFunc(this);
}
private:
HealthCalcFunc HealthFunc;
};
///////////////////三优质、古典的Strategy模式/////////////////////////
class Gamecharacter;
class HealthCalcFunc
{
public:
virtual int calc(const Gamecharacter& gc) const
{}
};
HealthCalcFunc defaultHealthCalc;
class Gamecharacter
{
public:
explicit Gamecharacter(HealthCalcFunc
phcf = &defaultHealthCalc)
:pHealthCalc(phcf)
{}
int healthValue() const
{
return pHealthCalc->calc(this);
}
private:
HealthCalcFunc
pHealthCalc;
};

25竣贪、絕不重新定義繼承而來(lái)的non-virtual函數(shù)和繼承而來(lái)的缺省參數(shù)值

//絕對(duì)不重新定義繼承而來(lái)的non_virtual函數(shù),因?yàn)樗庆o態(tài)綁定
//絕對(duì)不重新定義繼承而來(lái)的缺省參數(shù)值巩螃,因?yàn)樗庆o態(tài)綁定
class Shape
{
public:
enum ShapeColor{Red,Green,Blue};//默認(rèn)第一個(gè)值為int類(lèi)型的0
virtual void Draw(ShapeColor color = Red) const = 0
{
cout<<"Shape::Draw "<<color<<endl;
}
};
class Rectangle:public Shape
{
public:
virtual void Draw(ShapeColor color = Green) const//缺省參數(shù)是靜態(tài)綁定演怎,重新定義沒(méi)有什么卵用
{

    cout<<"Rectangle::Draw "<<color<<endl;
}

};
class Circle:public Shape
{
public:
virtual void Draw(ShapeColor color) const//指針調(diào)用此函數(shù)時(shí),不需要指定參數(shù)值避乏;對(duì)象調(diào)用此函數(shù)時(shí)爷耀,需要指定參數(shù)值
{

    cout<<"Circle::Draw "<<color<<endl;
}

};

void main()
{
Shape* ps;
Shape* pc = new Circle;
Shape* pr = new Rectangle;
pc->Draw();//Circle::Draw 0
pr->Draw();//Rectangle::Draw 0
Circle cc;
Shape::ShapeColor color = Shape::Green;/////Green代表是在全局下尋找Green這個(gè)名字,而不是在Shape這個(gè)類(lèi)作用域下尋找
cc.Draw(color);//Circle::Draw 1
}
/////======================================/////
/////////////////////////////////////版本1 代碼

class Shape
{
public:
enum ShapeColor{Red,Green,Blue};//枚舉
void Draw(ShapeColor color = Red)
{
cout<<"Shape::Draw "<<color<<endl;
}
};
class Rectangle:public Shape
{
public:
void Draw(ShapeColor color = Green)
{

    cout<<"Rectangle::Draw "<<color<<endl;
}

};

void main()
{
Shape s;
s.Draw();//Shape::Draw 0
Rectangle r;
r.Draw();//靜態(tài)綁定,默認(rèn)參數(shù)沒(méi)有從基類(lèi)中獲取//Rectangle::Draw 1
}

////////////////////////////////////版本2 代碼

class Shape
{
public:
enum ShapeColor{Red,Green,Blue};
virtual void Draw(ShapeColor color = Red)
{
cout<<"Shape::Draw "<<color<<endl;
}
};
class Rectangle:public Shape
{
public:
virtual void Draw(ShapeColor color = Green)//重新定義繼承而來(lái)的缺省參數(shù)值拍皮,并沒(méi)有卵用
{

    cout<<"Rectangle::Draw "<<color<<endl;
}

};

void main()
{

Shape* pc = new Shape;
Shape* pr = new Rectangle;
pc->Draw();//Circle::Draw 0
pr->Draw();//Rectangle::Draw 0

}

////////////////////////////////////版本3代碼
class Shape
{
public:
enum ShapeColor{Red,Green,Blue};
void Show(ShapeColor color = Red)
{
cout<<"S SHOW"<<endl;
Draw(color);
}
private:
virtual void Draw(ShapeColor color = Red)
{
cout<<"Shape::Draw "<<color<<endl;
}
};
class Rectangle:public Shape
{
public:
void Show(ShapeColor color = Green)
{
cout<<"R SHOW"<<endl;
Draw(color);
}
private:
virtual void Draw(ShapeColor color = Green)
{

    cout<<"Rectangle::Draw "<<color<<endl;
}

};

void main()
{

Shape* pc = new Shape;
Shape* pr = new Rectangle;
pc->Show();//S SHOW Shape::Draw 0
pr->Show();//S SHOW Rectangle::Draw 0
Shape s;
Rectangle r;
s.Show();//S SHOW Shape::Draw 0
r.Show();//R SHOW Rectangle::Draw 1

}

26歹叮、用list來(lái)實(shí)現(xiàn)set

////////////用list來(lái)實(shí)現(xiàn)set,但list允許存在重復(fù)元素铆帽,set不可以?xún)?nèi)含重復(fù)元素
template<typename T>
class Set
{
public:
bool member(const T& item) const;
void insert(const T& item);
void remove(const T& item);
size_t size() const;
private:
list<T> rep;
};
template<typename T>
bool Set::member(const T& item) const
{
return std::find(rep.begin(),rep.end(),item) != rep.end();
}
template<typename T>
void Set::insert(const T& item)
{
if(!member(item))
rep.push_back(item);
}
template<typename T>
void Set::remove(const T& item)
{
typename list<T>::iterator it = std::find(rep.begin(),rep.end(),item);
if(it!=rep.end())
rep.erase(it);
}
template<typename T>
size_t size() const
{
return rep.size();
}

27咆耿、private繼承可以造成Empty base最優(yōu)化

class Empty{};
class Base1
{
public:
private:
int x;
Empty y;
};

class Base2:private Empty
private:
int x;
};
void main()
{
cout << sizeof(Base1) <<" "<< sizeof(Base2)<< endl;//8 4
}

28、模板

(1)爹橱、模板規(guī)則
//對(duì)class 而言接口是顯式的萨螺,多態(tài)則是通過(guò)虛函數(shù)發(fā)生于運(yùn)行期
//對(duì)template而言接口是隱式的,多態(tài)則是通過(guò)template具現(xiàn)化和函數(shù)重載解析發(fā)生于編譯期。
template<class T>//class和typename可以互換
class Base{}慰技;
template<typename T>
class Derived{};

template<typename T>
class Derived:public Base<T>::Nested//不允許在基類(lèi)列typename
{
public:
explicit Derived(int x)
:Base<T>::Nested(x)//不允許在成員初值列加上typename
{
typename Base<T>::Nested temp;//在嵌套從屬類(lèi)型名稱(chēng)的前面需要加上typename
}
};

template<typename IterT>
void WorkWithIterator(IterT iter)
{
typedef typename std::iterator_traits<IterT>::value_type value_type;//若IterT是vector<int>::iterator,則temp的類(lèi)型就是int
value_type temp(*iter);
}

template<class T>//聲明成員模板用于泛化copy構(gòu)造和泛化assignment操作椭盏,還是需要聲明正常的copy構(gòu)造函數(shù)和assignment操作符
class shared_ptr
{
public:
shared_ptr(shared_ptr const& r);

template<class Y>
shared_ptr(shared_ptr<Y> const& r);

shared_ptr& operator=(shared_ptr const& r);

template<class Y>
shared_ptr& operator=(shared_ptr<Y> const& r);

};

//當(dāng)我們編寫(xiě)一個(gè)類(lèi)模板,而它所提供的與此模板相關(guān)的函數(shù)支持所有參數(shù)之隱式類(lèi)型轉(zhuǎn)換惹盼,請(qǐng)將那些函數(shù)定義為類(lèi)模板內(nèi)部的friend函數(shù)
template<typename T>
class Rational
{
public:
Rational(const T& numerator=0,
const T& denominator=1);
const T numerator() const;
const T denominator() const;
//將函數(shù)寫(xiě)在類(lèi)內(nèi)部是因?yàn)樽屵@個(gè)函數(shù)自動(dòng)具現(xiàn)化
friend const Rational operator* (const Rational& lhs,const Rational& rhs)//聲明為friend是因?yàn)樵陬?lèi)內(nèi)部聲明non-member函數(shù)唯一方法是令它成為一個(gè)friend
{
return Rational(lhs.numerator() * rhs.numerator(),lhs.denominator() * rhs.denominator());
}

};
//為了讓類(lèi)型轉(zhuǎn)換發(fā)生在所有實(shí)參身上庸汗,所以定義non-member函數(shù)
template<typename T>
const Rational<T> operator* (const Rational<T>& lhs,const Rational<T>& rhs)
{}

(2)惫确、模板特化
class Companya
{
public:
void sendClearText(const string& msg)
{
cout<<"Companya::sendClearText"<<endl;
}
void sendEncrypted(const string& msg)
{
cout<<"Companya::sendEncrypted"<<endl;
}
};

class Companyb
{
public:
void sendClearText(const string& msg)
{
cout<<"Companyb::sendClearText"<<endl;
}
void sendEncrypted(const string& msg)
{
cout<<"Companyb::sendEncrypted"<<endl;
}
};

class MsgInfo{};//用來(lái)保存信息手报,以備將來(lái)產(chǎn)生信息

template<typename Company>
class MsgSender
{
public:
void sendClear(const MsgInfo& info)
{
string msg;
Company c;
c.sendClearText(msg);
}
void sendSecret(const MsgInfo& info)
{}
};

class Companyz
{
public:
void sendEncrypted(const string& msg);
};

template<>//一個(gè)特化版的MsgSender template,在template實(shí)參是Companyz時(shí)被使用,這是模板全特化
class MsgSender<Companyz>
{
public:
void sendSecret(const MsgInfo& info)
{}
};

template<typename Company>
class LoggingMsgSender:public MsgSender<Company>
{
public:
void sendClearMsg(const MsgInfo& info)
{
sendClear(info);//調(diào)用基類(lèi)的函數(shù)改化,無(wú)法通過(guò)編譯
//this->sendClear(info);
}
};
void main()
{
LoggingMsgSender<Companya> aMsgSender;
MsgInfo msgData;
aMsgSender.sendClearMsg(msgData);
LoggingMsgSender<Companyz> zMsgSender;
//zMsgSender.sendClearMsg(msgData);//無(wú)法通過(guò)編譯掩蛤,因?yàn)樘鼗娴腗sgSender在實(shí)參是Companyz時(shí)沒(méi)有sendClear函數(shù)
}
(3)、模板造成的代碼膨脹及解決方法
template<typename T,size_t n>
class SquareMatrix
{
public:
void invert();
};
void main()
{
SquareMatrix<double,5> sm1;//具現(xiàn)化兩份代碼陈肛,造成代碼膨脹
sm1.invert();
SquareMatrix<double,10> sm2;
sm2.invert();
}
//因非類(lèi)型參數(shù)而造成的代碼膨脹揍鸟,采用以函數(shù)參數(shù)或class成員變量替換template參數(shù)來(lái)達(dá)到消除
//因類(lèi)型參數(shù)而造成的代碼膨脹,讓帶有完全相同的二進(jìn)制表述的具現(xiàn)類(lèi)型共享實(shí)現(xiàn)碼
template<typename T>
class SquareMatrixBase
{
protected:
void invert(size_t matrixSize);
};
template<typename T,size_t n>
class SquareMatrix:private SquareMatrixBase<T>
{
private:
using SquareMatrixBase<T>::invert;
public:
void invert()
{
this->invert(n);
}
};

29句旱、元編程計(jì)算階乘

template<unsigned n>
struct Factorial
{
enum{value = n*Factorial<n-1>::value};
};

template<>
struct Factorial<0>
{
enum{value = 1};
};

30阳藻、理解bad_alloc

class A
{
public:
A(int x):data(x){;}
void Show(){cout<<data<<endl;}
private:
int data;
};
//bad_alloc就像A一樣 是一個(gè)類(lèi)
void fun(int x)throw(A)
{
if(x > 10) throw A(12);

}
void main()
{
try
{
fun(12);
}
catch(A &ra)
{
cout<<"hello"<<endl;//輸出hello
}
}

31、理解new

(1)谈撒、set_new_handler
void outofmem()
{
cerr<<"unable to satisfy request for memory\n";
abort();
}
void main()
{
set_new_handler(outofmem);//指定new失敗時(shí)腥泥,調(diào)用的函數(shù)
//int *p = new int[10000000000000];////有一些編譯器里面 如果new 一個(gè)特別特別大的數(shù)字的話,那么編譯器會(huì)這樣處理new int[0],即申請(qǐng)0字節(jié)
int *p = new int[0x1234];
delete []p;
}
(2)啃匿、new的底層實(shí)現(xiàn)

typedef void (new_handler) ()
void
operator new(size_t size) throw(bad_alloc)//這是函數(shù)列表的一部分蛔外,表示不拋出異常 ,如果要拋出異常則參考
{
if(size == 0)
size = 1;
while(true)
{
//分配內(nèi)存溯乒;
if(分配成功)
return 指針;
new_handler globalHandler=set_new_handler(0);
set_new_handler(globalHandler);
if(globalHandler)
(*globalHandler)();
else throw bad_alloc();
}
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末夹厌,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子裆悄,更是在濱河造成了極大的恐慌矛纹,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件光稼,死亡現(xiàn)場(chǎng)離奇詭異或南,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)钟哥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)迎献,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人腻贰,你說(shuō)我怎么就攤上這事吁恍。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵冀瓦,是天一觀的道長(zhǎng)伴奥。 經(jīng)常有香客問(wèn)我,道長(zhǎng)翼闽,這世上最難降的妖魔是什么拾徙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮感局,結(jié)果婚禮上尼啡,老公的妹妹穿的比我還像新娘。我一直安慰自己询微,他們只是感情好崖瞭,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著撑毛,像睡著了一般书聚。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上藻雌,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天雌续,我揣著相機(jī)與錄音,去河邊找鬼胯杭。 笑死驯杜,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的歉摧。 我是一名探鬼主播艇肴,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼叁温!你這毒婦竟也來(lái)了再悼?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤膝但,失蹤者是張志新(化名)和其女友劉穎冲九,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跟束,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莺奸,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冀宴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片灭贷。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖略贮,靈堂內(nèi)的尸體忽然破棺而出甚疟,到底是詐尸還是另有隱情仗岖,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布览妖,位于F島的核電站轧拄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏讽膏。R本人自食惡果不足惜檩电,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望府树。 院中可真熱鬧俐末,春花似錦、人聲如沸挺尾。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遭铺。三九已至,卻和暖如春恢准,著一層夾襖步出監(jiān)牢的瞬間魂挂,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工馁筐, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留涂召,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓敏沉,卻偏偏與公主長(zhǎng)得像果正,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子盟迟,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容