Если есть два объекта: A и B, то можно сказать, что B is-a A, если в программе везде, где используется A, можно использовать B. Несмотря на мудреное определение, все просто. Если у меня есть базовый класс CPrinter и я от него наследую CEpson, CHP и т.п., то логично будет чтобы функция, которая принимает в качестве параметра CPrinter, могла работать с любым отнаследованным принтером, поскольку по логике вещей CEpson is-a CPrinter.
Есть такое хорошее правило, если в программе есть публичное наследование, то оно должно являть собой is-a отношение. И это та вещь, которую компилятор не сделает автомагически, ответственность за то, чтобы публичное наследование было is-a отношением лежит на программисте. Например:
Если я где-то определила публичное наследование вида:
class CBase
{
public:
virtual void VirtFunc();
// ...
};
class CDerived : public CBase
{
public:
virtual void VirtFunc();
// ...
};
void SomeFunc( const CBase& );
То я фактически говорю, что CDerived is-a CBase, а значит, что в функцию SomeFunc можно передавать как экземпляры CDerived, так и CBase, и они должны обрабатываться корректно. А если я реализовала функцию VirtFunc таким образом, что передавать в SomeFunc экземпляр CDerived по каким-либо причинам нельзя, то это как минимум странно.
Ссылки по теме:
comp.object IS A and HAS A relationships
GotW #40: Controlled Polymorphism
Еще есть принцип LSP, который как раз и приводит к правилу is-a.
ОтветитьУдалитьПринцип подстановки Лисков — Википедия.