2014-10-15 3 views
1

Мне интересно найти примеры, когда наследование алмазов - это хорошо. Я только теоретически читаю и не преуспеваю в этом на практике.Есть ли у вас примеры, когда наследование алмазов полезно?

+3

«Хорошая вещь» несколько субъективна, но на самом деле * используется * на практике, происходит ближе к дому, чем вы можете ожидать: [C++ io streams] (http://en.cppreference.com/w/cpp/IO). Вы, вероятно, использовали его, даже не подозревая, что он даже там. – WhozCraig

+1

Алмаз библиотеки std :: iostream может быть примером –

+2

В программном обеспечении на основе интерфейса иногда случается, что ваш общедоступный класс «интерфейса» опускается из какой-то абстрактной базы, а ваш частный класс impl нисходит как из этого публичного класса, так и из конкретного реализация одной и той же абстрактной базы. – dlf

ответ

3

Лучший пример наследования алмазов - std :: iostream library. Такой дизайн требует тщательного тестирования. В общем, мы должны избегать такого типа структуры, насколько это возможно, чтобы впоследствии уменьшить проблемы с обслуживанием.

1

Он иногда появляется в интерфейсном программировании, хотя вы можете избежать его, если будете осторожны. Это, вероятно, лучше всего иллюстрируется примером; в противном случае описание будет просто превратиться в салате слова:

// Foo.h 

struct IFoo 
{ 
    virtual ~IFoo() {} 
    virtual int Bar() = 0; 
    virtual int Baz() = 0; 
}; 


// FooBase.h 

#include "Foo.h" 

class FooBase : public IFoo 
{ 
public: 
    int Bar() override { return 0; } // default implementation 
    int Baz() override { return 0; } // default implementation 
}; 


// ConcreteFoo.h 

#include "Foo.h" 

class ConcreteFoo : public IFoo 
{ 
public: 
    static ConcreteFoo* Create(); 
    virtual void SayHello() = 0; 
}; 


// ConcreteFoo.cpp 

#include "ConcreteFoo.h" 
#include <iostream> 

class ConcreteFooImpl : public ConcreteFoo, public FooBase 
// Diamond! Both ConcreteFoo and FooBase descend from IFoo. 
{ 
public: 
    int Bar() override { return 1; } 

    // use default Baz() from FooBase 

    void SayHello() override { std::cout << "Hello!"; } 
}; 

ConcreteFoo* ConcreteFoo::Create() 
{ 
    return new ConcreteFooImpl(); 
} 

Когда вы пишете новый код, вы можете вообще не создавать такого рода договоренности, в первую очередь. Но если вы рефакторинг, чтобы разорвать зависимости в устаревшем коде, вы иногда получаете что-то, что напоминает выше, как остановку по пути (или, может быть, последнюю остановку, в зависимости от того, насколько это вас беспокоит :)).