2009-10-28 66 views
2

一勞永逸,我想澄清這個有些主觀和議論性的編程領域。多重遺傳,多態性和更新的編程方式

多inheritnace

在我目前的工作enviornment我有C++開發人員和來自完全以不同的世界,因而對規劃佈局不同的意見C#開發人員。

現在我正在成爲C#和Java開發人員,我從來沒有到過需要使用多繼承的狀態,但是我周圍的C++開發人員傾向於通過諸如「這將是一個完美的方式來使用多個繼承「

當然,我傾向於不同意。

我的問題

在什麼情況下會多重繼承是解決比使用接口的問題,更好或更簡單的方法,只是簡單的繼承?

你可以總是通過使用ie成員變量來解決多重繼承的好處嗎?

+0

一個很好的例子爲MI,我能想到的將是一個科學模型級輕型的,它是一個兩波和粒子。 – snicker 2009-10-28 14:07:35

回答

3

除了你似乎建議使用多重繼承。

繼承有不同的用途。公共繼承指定一個IS-A關係,並且與任何訪問修飾符的繼承可以爲子類提供行爲,然後可以覆蓋它。在C#和Java(我更熟悉)中,接口提供了沒有任何行爲的IS-A接口。 (在C++中,你可以通過定義一個沒有數據成員和純虛擬函數的類來實現接口)。完整的C++風格的繼承。你只是把它分解成組件並且花更多的麻煩去做。這個描述是解決多重繼承的問題是不真誠的,因爲這樣做有兩個接口和兩個成員變量是多重繼承。如果要以多態方式修改行爲,它會變得更加尷尬,因爲您需要並行繼承層次結構或更復雜的調度到成員變量。

C++多重繼承存在問題,屬實,但也存在不存在問題的用法。我看到的第一個很好的用法是「混合」:小班級添加某些行爲。 Java中有很多這些接口,但你需要自己處理這些行爲。

如果您有興趣瞭解更多關於多重繼承,我建議您嘗試使用語言,如Common Lisp的,在多重繼承的常規使用,沒有人有這問題。

4

多重繼承是一個不錯的功能。那些曾經用MI編寫代碼的人自然會從不同的角度來解決問題。然而,對於一個程序員來說,「更容易」對另一個程序員來說可能「更難」。
對於C++有關MI具體信息見Herb Sutter's文章:

結合模塊/庫

很多類被設計爲基礎 類;也就是說,要使用它們,你是 意圖從它們繼承。 自然的後果:如果你想 寫一個擴展兩個 庫的類,並且你需要從每個類的類繼承 怎麼辦?因爲 你平時沒有的 改變庫代碼的選項(如果你 從 第三方供應商購買的圖書館,或者是通過其他的項目團隊 公司內部生產的模塊 ),MI是必要。

易於(多形態)的使用

有示例,其中允許MI 極大地簡化使用相同 對象多態在不同 方式。一個很好的例子是在 C++ PL3 14.2.2發現其證明爲異常類的 基於MI-設計, 其中最衍生的異常類 可以具有多晶型IS-A 與多個直接基 類關係。

0

我還沒有多次使用多重繼承,但有時它很方便,因爲它性能良好,降低了維護成本。 答案有一些很好的場景。

1

已經廣泛使用了兩種語言,其中一種具有(Python)多重繼承,另一種不具有(C#)我可以誠實地說我有從不使用或需要使用MI。

我傾向於在大多數情況下比正常繼承和/或多繼承更喜歡接口+組合。當然,有些情況下你確實需要繼承,特別是在C#中 - 但MI?決不。

編輯:如果你能展示一個你的C++程序員主張MI而你沒有的例子,它會更容易回答。

編輯:關於它的思考多一點,我意識到,像C#或C++和鴨類型語言如Python靜態類型語言之間的差異可能是一個很好的原因,我從來沒有在Python中使用MI,只是由於它的動態性。但是,我還沒有用過C#的需求。

0
#include <afx.h>  
#include <afxtempl.h> 
#include "StdAfx.h" 

class Employee 
{ 
    char name[30]; 
public: 
    Employee() {} 
    Employee(const char* nm) 
    { 
     strcpy(name, nm) ; 
    } 
    char* getName() const; 
    virtual double computePay() const = 0; 
    virtual ~Employee() 
    { 
    } 
}; 

class WageEmployee : public virtual Employee 
{ 
    double wage; 
    double hours; 
public: 
    WageEmployee(const char* nm); 
    void setWage( double wg ){wage = wg; } 
    void setHours(double hrs){hours = hrs;} 

    double computePay() const  /* Implicitly virtual */ 
    { 
     return wage * hours; 
    } 
}; 

class SalesPerson : public WageEmployee 
{ 
     double commission; 
     double salesMade; 
public: 
     SalesPerson(const char* nm); 
     void setCommission(double comm) 
     { 
      commission = comm; 
     } 
     void setSales(double sales) 
     { 
      salesMade = sales; 
     } 

     double computePay() const  /* Implicitly virtual */ 
     { 
      return WageEmployee::computePay() + commission * salesMade; 
     } 
}; 

class Manager : public virtual Employee 
{ 
    double weeklySalary; 
public: 
    Manager(const char* nm); 

    void setSalary(double salary){weeklySalary = salary; } 

    double computePay() const   /* Implicitly virtual */ 
    { 
     return weeklySalary; 
    } 
}; 

class SalesManager : public SalesPerson, public Manager 
{ 
public: 
    SalesManager::SalesManager(const char* nm) 
       :Employee(nm),Manager(nm),SalesPerson(nm) 
    { 
    } 

    double computePay() const  /* Implicitly virtual */ 
    { 
     return Manager::computePay() + SalesPerson::computePay(); 
    } 
}; 

typedef CTypedPtrList < CPtrList, Employee* > CEmployeeList; 

class EmployeeList 
{ 
    CEmployeeList List; 
public: 
    EmployeeList() {} 
    CEmployeeList& GetElements() { return List; } 

    void Add(Employee* newEmp) 
    { 
     List.AddTail(newEmp) ;   
    } 

    virtual ~EmployeeList() 
    { 
     POSITION pos = List.GetHeadPosition() ; 
     while (pos != NULL) 
     { 
      delete List.GetNext(pos) ; 
     } 
     List.RemoveAll() ; 
    } 
}; 


WageEmployee::WageEmployee(const char* nm) 
      :Employee(nm) 
{ 
    wage = 0.0; 
    hours = 0.0; 
} 

SalesPerson::SalesPerson(const char* nm) 
      :WageEmployee(nm) 
{ 
    commission = 0.0; 
    salesMade = 0.0; 
} 

Manager::Manager(const char* nm) 
     :Employee(nm) 
{ 
    weeklySalary = 0.0; 
} 

void main(int argc, char *argv[]) 
{ 
    int ans = 0 ; 

EmployeeList myDept; 
WageEmployee* wagePtr; 
SalesPerson* salePtr; 
Manager*  mgrPtr; 
SalesManager* smPtr; 

wagePtr = new WageEmployee("Alan Wage"); 
salePtr = new SalesPerson("Brian Sale"); 
mgrPtr = new Manager("Clive Manager"); 
smPtr = new SalesManager("David SaleManager"); 

wagePtr->setWage(10.0); 
wagePtr->setHours(35.0); 

salePtr->setWage(5.0); 
salePtr->setHours(35.0); 
salePtr->setCommission(0.05); 
salePtr->setSales(100.0); 

mgrPtr->setSalary(600.0) ; 

smPtr->setSalary(670.0) ; 
smPtr->setCommission(0.01); 
smPtr->setSales(100.0); 


myDept.Add(wagePtr); 
myDept.Add(salePtr); 
myDept.Add(mgrPtr); 
myDept.Add(smPtr); 

double payroll = 0.0 ; 
Employee* person ; 
POSITION pos = myDept.GetElements().GetHeadPosition() ; 
while (pos != NULL) 
{ 
    person = (Employee*)myDept.GetElements().GetNext(pos) ; 
    payroll += person->computePay(); 
} 

ExitProcess(ans) ; 
} 

上面是具有多重繼承的Visual C++。

using System; 
using System.IO; 
using System.Collections; 
using System.Collections.Generic; 

namespace ConsolePoly 
{ 
    interface Employee 
    { 
     string Name { get; set; } 
     double computePay(); 
    } 

class WageEmployee : Employee 
{ 
    private string iName = ""; 
    virtual public string Name { get { return iName; } set { iName = value; } } 

    public double wage { get; set; } 
    public double hours { get; set; } 

    public WageEmployee(string nm) 
    { 
     Name = nm; 
     wage = 0.0; 
     hours = 0.0; 
    } 

    virtual public double computePay() { return wage * hours; }  /* Implicitly virtual c++ */ 
} 

class SalesPerson : WageEmployee 
{ 
    public double commission { get; set; } 
    public double salesMade { get; set; } 

    public SalesPerson(string nm) 
     : base(nm) 
    { 
     commission = 0.0; 
     salesMade = 0.0; 
    } 

    override public double computePay() 
    { 
     return base.computePay() + commission * salesMade; 
    } /* Implicitly virtual c++ */ 
} 

class Manager : Employee 
{ 
    private string iName = ""; 
    virtual public string Name { get { return iName; } set { iName = value; } } 
    public double weeklySalary { get; set; } 

    public Manager(string nm) 
    { 
     Name = nm; 
     weeklySalary = 0.0; 
    } 
    public Manager() 
    { 
     weeklySalary = 0.0; 
    } 

    public double computePay() { return weeklySalary; }  /* Implicitly virtual c++ */ 
} 

class SalesManager : Manager, /*SalesPerson,*/ Employee 
{    
    public SalesManager(string nm) 
    { 
     Name = nm; 
     //SalesPerson(nm); 
     //commission = 0.01; 
     //salesMade = 100.0; 
    } 

    public double computePay() { return base.computePay();/*Manager.computePay()+SalesPerson.computePay();*/ }  
} 

class EmployeeList 
{ 
    private List<Employee> list = new List<Employee>(); 
    public List<Employee> GetElements() { return list; } 
    public void Add(Employee newEmp) { list.Add(newEmp);} 
    public EmployeeList() {} 
} 


class poly 
{ 
    public poly() 
    { 

    } 

    public virtual void generate() 
    { 
     EmployeeList myDept = new EmployeeList(); 

     WageEmployee wagePtr = new WageEmployee("Alan Wage"); 
     SalesPerson salePtr = new SalesPerson("Brian Sale"); 
     Manager mgrPtr = new Manager("Clive Manager"); 
     SalesManager salemanPtr = new SalesManager("David SaleMan"); 

     wagePtr.wage=10.0; 
     wagePtr.hours=35; 

     salePtr.wage= 5.0 ; 
     salePtr.hours= 35.0 ; 
     salePtr.commission= 0.05 ; 
     salePtr.salesMade= 100.0 ; 

     mgrPtr.weeklySalary=600.0; 
     salemanPtr.weeklySalary = 670; 

     myDept.Add(wagePtr); 
     myDept.Add(salePtr); 
     myDept.Add(mgrPtr); 
     myDept.Add(salemanPtr); 

     double payroll = 0.0 ; 

     List<Employee> list = myDept.GetElements(); 

     foreach (Employee person in list) 
     { 
      Console.WriteLine("personName(\"{0}\")\tcomputePay(\"{1}\")", person.Name, person.computePay()); 
      payroll += person.computePay(); 
     } 
     Console.WriteLine("computePay(\"{0}\")\n", payroll.ToString()); 

    } 

    static void Main(string[] args) 
    { 
     try 
     { 
      new poly().generate(); //new poly(args[0], args[1]).generate(); 
     } 
     catch (IndexOutOfRangeException ioe) 
     { 
      System.Console.Error.WriteLine(ioe); 
     } 
    } 
} 

} 

但在C#中SalesManager的多重繼承不支持語言。

我個人很高興失去多重繼承。