C++基礎::拾遺&&瑣碎

Inside_Zhang發表於2015-11-17

hpp vs cpp

  • hpp:類宣告(declaration)

  • cpp:類實現(definition)

拷貝構造存在的前提

忽然想到這麼一個有意思的話題,拷貝構造(copy ctor)或者賦值構造(assignment ctor)存在的前提是存在一個別的什麼構造比如預設構造或者一個含引數的構造,總之,你不能空手套白狼。

異常會中斷後續程式的進行

int main(int, char**)
{
    try
    {
        throw std::exception("hello exception");
        std::cout << "you cannot see me!" << std::endl;
                        // 這句話不會被執行
    }
    catch(std::exception& e)
    {
        std::cout << e.what() << std::endl;
    }
    return 0;
}

default constructor

class A
{
public:
    A() { std::cout <<"A::A()" << std::endd;}
};

class B
{
public:
    A _a;
};

int main(int, char**)
{
    B b;
            // 會在控制檯介面列印"A::A()"
            // 證明預設建構函式會初始化每一位成員變數
    return 0;
}

要特別注意的是,初始化每一位成員變數用的是其成員變數自身的預設建構函式

class A
{
public:
    A(int) { cout << "A::A(int)" << endl;}
            // 顯式提供給類一個建構函式之後,
            // 編譯器會收回為它提供的那些預設建構函式(無參建構函式)
}

class B
{
private:
    A _a;
}

int main(int, char**)
{
    B b;
            // 此時編譯出錯   
            // B的預設建構函式初始化其成員變數時,未找到其無參預設建構函式
    return 0;
}

編譯器就是這麼矯情,如果你提供了另外的建構函式,無論是含參的還是copy 構造或是賦值構造,它就不會在為你提供預設構造。

我們再來看一個更為典型的例子:

class Widget
{
public:
    Widget(){ cout << "Widget::Widget()" << endl;}
}

class Test
{
private:
    shared_ptr<Widget> _widget;
public:
    shared_ptr<Widget> widget() { return _widget;}
    const shared_ptr<Widget> widget() const { return _widget;}
}

int main(int, char**)
{
    Test t;
            // 什麼也沒有輸出
            // t的預設建構函式會初始化會分別呼叫其成員函式的預設建構函式
            // shared_ptr<Widget>物件型別的預設建構函式不僅不會呼叫
            // Widget的預設建構函式,而且是什麼也不做,這一點可參閱其原始碼 
    return 0;
}

這就牽涉到智慧指標物件的構造問題了,呼叫一個其預設建構函式什麼工作也不會做,只有當拷貝構造,或者賦值構造發生時,才會進行真正的構造工作:

int main(int, char**)
{
    Test t;
    shared_ptr<Widget> w(new Widget);
    t.widget() = w;
    return 0;
}

friend

一個類內部的有友元函式宣告不是類內部的一部分,因此不受訪問修飾的影響,放在一個類宣告的任何位置都是等效的。

繼承關係中的父類的虛擬函式

繼承關係中的父類的非純虛擬函式要給出實現。

class Base
{
public:
    void foo();                 // 可以不給出實現,但當呼叫Base物件(如果Base不是抽象基類)的foo函式時才會發生解析錯誤
    virtual void fooA(){}       // 只有派生類A才能使用的介面
    virtual void fooB(){}       // 只有派生類B才能使用的介面
    virtual void func() = 0;    // 子類必須提供該純虛擬函式的實現方可進行例項化
};

class DerivedA :public Base
{
public:
    void fooA() {}  
    void func() {}
}

class DeriveB :public Base
{
public:
    void fooB() {}
    void func() {}
}

int main(int, char**)
{
    DerivedA da;
    DerivedB db;
    da.foo();     // 訪問基類中的foo(),前提是Base提供實現

    da.fooA();
    da.fooB();
    return 0;
}

相關文章