class Grandfather { public: int field; };
class LeftFather : Grandfather {};
class RightFather : Grandfather {};
class Son : LeftFather, RightFather {};
void foo(LeftFather& x) { x.field = 42; }
InputStream.remainder() { return size() - pos(); }
).std::vector<std::unique_ptr<SomeBase>>
. QVariant SomeModel::data(
const QModelIndex &index, int role = Qt::DisplayRole) const override {}
#include <iostream>
class Vocal { // интерфейс
public:
virtual void shout() = 0;
virtual ~Vocal() = default;
};
class Dog : public Vocal {
public:
virtual void shout() override { std::cout << "Woof!" << std::endl; }
};
class Unrelated {};
// ВАРИАНТ 1. Метод выкручивания рук.
void shoutAll_v1(Vocal** x, int n)
{
for (int i = 0; i < n; ++i)
x[i]->shout();
}
template <class T, int N>
inline void shoutAll_v1(T* (&x)[N]) {
// Тупая проверка концепции, ждём Си++20
static_assert (std::is_base_of<Vocal, T>(), "Need array of Vocal");
T** xx = x;
shoutAll_v1(reinterpret_cast<Vocal**>(xx), N);
}
// ВАРИАНТ 2. Виртуальный полиморфизм.
class Choir { // интерфейс
public:
virtual int size() const = 0;
virtual Vocal& at(size_t i) const = 0;
virtual ~Choir() = default;
};
void shoutAll_v2(const Choir& x)
{
int sz = x.size();
for (int i = 0; i <sz; ++i)
x.at(i).shout();
}
template <class T>
class VocalArray : public Choir {
public:
template <int N>
VocalArray(T* (&x)[N]) : fData(x), fSize(N) {}
int size() const override { return fSize; }
Vocal& at(size_t i) const override { return *fData[i]; }
private:
T** const fData;
int fSize;
};
int main()
{
Dog* sons[3];
for(auto& x : sons) {
x = new Dog;
}
//Unrelated* unrel[3];
std::cout << "V1" << std::endl;
shoutAll_v1(sons);
//shoutAll_v1(unrel); не компилируется
std::cout << "V2" << std::endl;
shoutAll_v2(VocalArray<Dog>(sons));
//shoutAll_v2(VocalArray<Unrelated>(unrel)); не компилируется
return 0;
}
LSP предписывает наследникам сохранять поведение (контракт) базового класса.
class Button {
protected void paint(Canvas aCanvas) {}
}
class MyButton extends Button {
@Override
protected void paint(Canvas aCanvas) {}
}
interface Button {
void press();
boolean state();
void addListener(ButtonListener x);
}
class GameObject {
void paint(Renderer renderer);
}
class MyButton extends GameObject implements Button {
}
class FridgeGame implements ButtonListener { // помните, такая была в «Братьях Пилотах»?
Button buttons[][] = new MyButton[4][4];
}
#pragma pack(1)
struct FileHeader
struct MAPINFO
// virtual
unsigned long long Stream::remainder() const { return size() - pos(); }
HandleStream::HandleStream(HANDLE aHandle) : fHandle(aHandle) {}
HandleStream::~HandleStream() { close(); }
void HandleStream::close()
{
if (Handle != INVALID_HANDLE) { // не помню, как там эта константа в Win32
CloseHandle(fHandle);
fHandle = INVALID_HANDLE;
}
}
using EvClick = void (*)();
Class Model{
public:
void click() { if (fOnClick) fOnClick(); }
void setOnClick(EvClick x) { fOnClick = x; }
private:
EvClick fOnClick = nullptr;
}
class ClickEvent {
public:
int x, y;
virtual ~ClickEvent();
}
using EvClick = void (*)(ClickEvent&);