2020年2月2日 星期日

overwrite override overload 還有encapsulation

最近我弟在讀計概,書裡講到了這幾個詞搞不清楚,我也有點忘了,所以也整理一下,建議就算是不熟悉程式的人還是盡量以記英文為主。


  1. overload(多載) : 相同的function名稱,根據不同的傳入參數來呼叫對應的function
  2. override(覆寫): 在繼承的時候覆寫父類別的function
  3. overwrite(重寫):  在繼承的時候利用指標轉型重寫父類別的function
  4. encapsulation(封裝): 用抽象的函式介面寫出架構,再用override/overwrite改寫細節

  • overload 

個人覺得overload最好懂,這就是相同的function名稱,根據不同的傳入參數來呼叫對應的function,就算是C也可以這樣寫喔。參考以下的code
#include<iostream>
using namespace std;

void PrintAdd(int X,int Y){
 cout <<"PrintIntAdd: " << X+Y << endl;
}
void PrintAdd(double X,double Y){
 cout << "PrintdoubleAdd: " << X+Y <<endl;
}

int main()
{
    PrintAdd(1,2);
    PrintAdd(0.1,0.2);
    cin.get();
    return 0;
}



console output:
PrintIntAdd: 3
PrintdoubleAdd: 0.3


這個特性的主要好處是可以大幅提升維護性,程式運算意義相同的function寫一樣的名字,避險寫了func1,func2...弄了一堆代號讓自己記不起來,造成維護的困擾。對了,寫override的時候function一定要帶virtual修飾字喔!

  • override  

overwite特性主要用在class的繼承(inheritance)上,在工程設計上,我們都會避免做重工,因此可以共用的模組就會重複使用,就像forloop重複的程式就用迴圈減少行數,或是寫function相同功能就用呼叫function而複製貼上程式碼。以下用一個簡單的會員範例來舉例
#include<iostream>
using namespace std;

class BaseMember
{
public:
    virtual void InitMoney(int i){ cout << "BaseMember::InitMoney(int) : " << i << endl;}
};

class VIP_Member : public BaseMember
{
public:
    virtual void InitMoney(int i){ cout << "VIP_Member::InitMoney(int) : " << i+9999 << endl;}
};
int main()
{
    BaseMember b;
    BaseMember * vip_b = new VIP_Member();   //特殊模式的會員 
    b.InitMoney(100);
    vip_b->InitMoney(100);                 

    delete vip_b;
    cin.get();
    return 0;
}


console output:
BaseMember::InitMoney(int) : 100
VIP_Member::InitMoney(int) : 10099




  • overwrite  

C++獨友的功能,java沒有喔!我覺得這個比較複雜一點,我參考了這個網址的內容與程式來解釋


#include 
using namespace std;

class Base
{
public:
    virtual void f(float x){ cout << "Base::f(float) " << x << endl; }
    virtual void g(float x){ cout << "Base::g(float) " << x << endl; }
    void h(float x){ cout << "Base::h(float) " << x << endl; }
};

class Derived : public Base
{
public:
    virtual void f(float x){ cout << "Derived::f(float) " << x << endl; }
    virtual void g(int x){ cout << "Derived::g(int) " << x << endl; }
    void h(float x){ cout << "Derived::h(float) " << x << endl; }
};

int main()
{
    Derived  d;
    Base *pb = &d;
    Derived *pd = &d;

    // Good : behavior depends solely on type of the object
    pb->f(3.14f); // Derived::f(float) 3.14
    pd->f(3.14f); // Derived::f(float) 3.14

    // Bad : behavior depends on type of the pointer
    pb->g(3.14f); // Base::g(float) 3.14 (surprise!)
    pd->g(3.14f); // Derived::g(int) 3

    // Bad : behavior depends on type of the pointer
    pb->h(3.14f); // Base::h(float) 3.14  (surprise!)
    pd->h(3.14f); // Derived::h(float) 3.14

    return 0;
}


console output:
Derived::f(float): 3.14
Derived::f(float): 3.14
Base::g(float): 3.14
Derived::g(int): 3
Base::h(float): 3.14
Derived::h(float): 3.14

在上面這個例子中:
  • 函式Derived::f(float)覆盖(override)了Base::f(float)。
  • 函式Derived::g(int)改寫/隱藏(overwrite)了Base::g(float)。
  • 函式Derived::h(float)改寫/隱藏(overwrite)了Base::h(float)。
1)如果繼承的函式與基礎類別的函式同名,但是參數不同。那此時,不論有無virtual關鍵字,基礎類別的函式將被隱藏(注意别與overload混淆)
2)如果繼承的函式與基礎類別的函式同名,且參數也相同,但是基礎類別没有virtual關鍵字。那此時,基礎類別的函式被隱藏(注意别與override混淆)


  • Encapsulation

最後想提封裝,這個詞最主要是我們在做設計的時候,會先把大架構做出來,細部的程式功能可以做調整,大架構會用抽象的函式介面寫出來(也就是前面看到的virtual function),實做的時候再用繼承或是override方式把細節做出來,目的跟先前講的一樣Don't repeatedly.