多重继承,多态和更新的编程方式

时间:2009-10-28 13:47:31

标签: architecture polymorphism

一劳永逸,我想澄清这个有点主观和争论的编程领域。

多重继承

在我目前的工作环境中,我有C ++开发人员和C#开发人员,他们来自不同的世界,因此对编程布局有不同的看法。

现在我自己是一名C#和Java开发人员,我从来没有进入过实际需要使用多重继承的状态,但我周围的C ++开发人员倾向于通过诸如“这将是使用多重继承的完美方式”之类的评论。 “

当然我倾向于不同意。

我的问题

在什么情况下,多继承是一种更好或更简单的方法来解决问题,而不是使用接口和简单的继承?

您是否可以通过使用ie成员变量来解决多重继承的好处?

6 个答案:

答案 0 :(得分:4)

多重继承是一个很好的功能。曾经用MI编写代码的人自然会从不同角度解决问题。然而,对于一个程序员来说“更容易”,对另一个程序员来说可能“更难”。
有关MI的C ++特定信息,请参阅Herb Sutter's文章:

  

组合模块/库

     

许多课程都是基础设计   班;也就是说,你使用它们   打算继承他们。该   自然结果:如果你想要怎么办?   写一个扩展两个的类   图书馆,你需要   从每个类中继承?因为   你通常没有选择   更改库代码(如果你   从a。购买图书馆   第三方供应商,或者它是一个模块   由另一个项目团队制作   在公司内部),MI是必要的。

     

易用(多态)使用

     

有一些允许MI的例子   大大简化了使用它   对象多态地不同   方法。一个很好的例子是在   C ++ PL3 14.2.2演示了一个   基于MI的异常类设计,   其中一个派生最多的异常类   可能有多态IS-A   与多个直接基地的关系   类。

答案 1 :(得分:3)

除了您似乎建议使用多重继承。

继承有不同的用途。公共继承指定IS-A关系,并且使用任何访问修饰符的继承可以为子类提供行为,然后可以覆盖该类。在C#和Java(我更熟悉)中,接口提供没有行为的IS-A接口。 (在C ++中,您可以通过定义一个没有数据成员且所有函数都是纯虚拟的类来创建接口。)

因此,如果您提供一个接口,并输入一个成员变量来提供行为,那么您正在进行完整的C ++样式继承。你只是把它分解成组件并且花费更多的麻烦去做。将此描述为解决多重继承问题是不诚实的,因为使用两个接口和两个成员变量进行多重继承。如果您要以多态方式修改行为,则会变得更加尴尬,因为您需要并行继承层次结构或对成员变量进行更复杂的调度。

C ++多重继承存在问题,但是也存在不存在问题的用途。我看到的第一个好处是“mix-ins”:小类可以添加某些行为。在Java中有很多这些接口,但是你应该自己处理这些行为。

如果您有兴趣了解有关多重继承的更多信息,我建议您尝试一种语言,例如Common Lisp,其中常规使用多重继承,并且没有任何问题。

答案 2 :(得分:1)

看一下这个SO主题:Should C# include multiple inheritance?

答案 3 :(得分:1)

广泛使用两种语言,其中一种具有(Python)多重继承而一种不具有(C#)我可以诚实地说我从未使用或需要MI。

在大多数情况下,我更倾向于使用接口+组合而不是正常继承和/或多继承。当然在某些情况下你确实需要继承,特别是在C#中 - 但MI?从不。

编辑:如果您可以展示一个C ++程序员提倡MI并且您没有提供MI的示例,那么回答会更容易。

编辑:更多地考虑一下我意识到像C#或C ++这样的静态类型语言和Python之类的鸭式语言之间的区别可能是我从未使用过的一个很好的理由Python中的MI,只是因为它的动态特性。但是,我仍然不需要在C#中使用它。

答案 4 :(得分:0)

我没有多次使用多重继承,但有时候,它很方便,因为它只是表现良好并降低了维护成本。 C++ FAQ Lite答案有一些很好的场景。

答案 5 :(得分: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的多重继承不支持语言。

我个人很高兴失去多重继承权。