Информация об изменениях

Сообщение Re[9]: как сократить количество vtbl от 25.04.2017 17:18

Изменено 25.04.2017 19:07 Erop

Re[9]: как сократить количество vtbl
Здравствуйте, qaz77, Вы писали:

Q>Здравствуйте, Erop, Вы писали:


Q>>>Если все перевести на NVI, то нельзя будет Bar'ы скармливать функциям, ожидающим полиморфное поведение.

Q>>>Либо все такие функции переделывать в шаблоны.

E>>Почему?

E>>С точки зрения клиентского кода вообще ничего, кроме того, что кастить надо иначе, не поменяется же?

Q>Функции ожидают параметр ISerializable& (к примеру) и зовут его виртуальные функции,

Q>т.е. полиморфизм времени выполнения в чистом виде.

Q>Если я для какого-то IBar: public ISerializable уберу наследование ISerializable

Q>и сделаю не виртуальные функции load, save и пр. одноименные членам ISerializable,
Q>то IBar нельзя будет скормить функциям, ожидающим ISerializable.

Почему?
// SuperBar.h
struct ISerializable;
struct IClonable;
struct IDeletable
//    И т. д...

class ISuperBar {
public:
    virtual operator ISerializable*() { return 0; }
    virtual operator IClonable*() { return 0; }
    virtual operator IDeletable*() { return to<IDeletable>(); }
    //    И т. д...

protected:
    template<typename I> I* to() { return (I*)this; }
    template<typename const I> I* to() const { return (const I*)this; }

    virtual ~ISuperBar() {}

    // ISerializable
    virtual void Serialize() { assert( false ); }

    // IClonable
    virtual ISuperBar* Clone() { assert( false ); }

    // IDeletable
    virtual void Delete() { delete this; }

    //    И т. д...

};

struct IDeletable : ISuperBar {
using ISuperBar::Delete;
};

////////////////////////////
// Serializable.h

#include <SuperBar.h>
struct ISerializable : ISuperBar {
using ISuperBar::Serialize;
};

////////////////////////////
// Clonable.h

#include <SuperBar.h>
struct IClonable : ISuperBar {
using ISuperBar::Clone;
};



Теперь тот, кто выводился из IClonable, может продолжать это делать, только лучше бы при этом ещё определить operator IClonable*
Но в целом для него ничего не поменяется, и для того, кто использует интерфейс IClonable не поменяется, за исключением того, что
нельзя запрашивать поддерживаемые интерфейсы через dynamic_cast.

Единственное что поменяется, так это если кто-то поддерживает несколько интерфейсов из ISuperBar, то он может вывестись просто публично из ISuperBar и реализовать нужные методы и операторы приведения

Q>Сделать полиморфное поведение (времени компиляции) по одноименным функциям-членам можно

Q>в шаблонной функции, когда не важно виртуальные функции-члены или нет.
Это место не понял о чём тут речь, но, IMHO, это не важно.


Q>Вот я и имел в виду, что если один из многих классов переделать на NVI,

Q>то тогда все функции, куда его передавали как абстрактный интерфейс, нужно из обычных функций переделывать в шаблонные:
Не нужно

struct CBar : ISuperBar {
    // ISerializable
    operator ISerializable*() { return to<ISerializable>(); }
    void Serialize() { /*реализация*/ }

    // IClonable
    operator IClonable*() { return to<IClonable>(); }
    IClonable* Clone() { /*реализация*/ }
};

class CFoo : public IClonable {
public:
    CFoo* Clone() { return new CFoo( *this ); }
};

void foo( IClonable* p ) { p->Clone()->operator IDeletable*()->Delete(); }

CBar b;
foo( b );

CFoo f;
foo( &f );

Как видишь ничего шаблонным делать не надо.

Q>полиморфизм времени выполнения использовать не получится, т.к. общей базы не будет.

Почему? ISuperBar жеж?

ISerializable это такое view на ISuperBar, в котором в public видны только методы ISerializable и всё.

То есть для программиста он останется таким же ISerializable, за исключением того, что QueryInterface иначе далать надо, а для С++ это будет просто NVI view на интерфейс, но это будет спрятано за protected
Re[9]: как сократить количество vtbl
Здравствуйте, qaz77, Вы писали:

Q>Если я для какого-то IBar: public ISerializable уберу наследование ISerializable

Q>и сделаю не виртуальные функции load, save и пр. одноименные членам ISerializable,
Q>то IBar нельзя будет скормить функциям, ожидающим ISerializable.

Почему?
// SuperBar.h
struct ISerializable;
struct IClonable;
struct IDeletable
//    И т. д...

class ISuperBar {
public:
    virtual operator ISerializable*() { return 0; }
    virtual operator IClonable*() { return 0; }
    virtual operator IDeletable*() { return to<IDeletable>(); }
    //    И т. д...

protected:
    template<typename I> I* to() { return (I*)this; }
    template<typename const I> I* to() const { return (const I*)this; }

    virtual ~ISuperBar() {}

    // ISerializable
    virtual void Serialize() { assert( false ); }

    // IClonable
    virtual ISuperBar* Clone() { assert( false ); }

    // IDeletable
    virtual void Delete() { delete this; }

    //    И т. д...

};

struct IDeletable : ISuperBar {
using ISuperBar::Delete;
};

////////////////////////////
// Serializable.h

#include <SuperBar.h>
struct ISerializable : ISuperBar {
using ISuperBar::Serialize;
};

////////////////////////////
// Clonable.h

#include <SuperBar.h>
struct IClonable : ISuperBar {
using ISuperBar::Clone;
};



Теперь тот, кто выводился из IClonable, может продолжать это делать, только лучше бы при этом ещё определить operator IClonable*
Но в целом для него ничего не поменяется, и для того, кто использует интерфейс IClonable не поменяется, за исключением того, что
нельзя запрашивать поддерживаемые интерфейсы через dynamic_cast.

Единственное что поменяется, так это если кто-то поддерживает несколько интерфейсов из ISuperBar, то он может вывестись просто публично из ISuperBar и реализовать нужные методы и операторы приведения

Q>Сделать полиморфное поведение (времени компиляции) по одноименным функциям-членам можно

Q>в шаблонной функции, когда не важно виртуальные функции-члены или нет.
Это место не понял о чём тут речь, но, IMHO, это не важно.


Q>Вот я и имел в виду, что если один из многих классов переделать на NVI,

Q>то тогда все функции, куда его передавали как абстрактный интерфейс, нужно из обычных функций переделывать в шаблонные:
Не нужно

struct CBar : ISuperBar {
    // ISerializable
    operator ISerializable*() { return to<ISerializable>(); }
    void Serialize() { /*реализация*/ }

    // IClonable
    operator IClonable*() { return to<IClonable>(); }
    IClonable* Clone() { /*реализация*/ }
};

class CFoo : public IClonable {
public:
    CFoo* Clone() { return new CFoo( *this ); }
};

void foo( IClonable* p ) { p->Clone()->operator IDeletable*()->Delete(); }

CBar b;
foo( b );

CFoo f;
foo( &f );

Как видишь ничего шаблонным делать не надо.

Q>полиморфизм времени выполнения использовать не получится, т.к. общей базы не будет.

Почему? ISuperBar жеж?

ISerializable это такое view на ISuperBar, в котором в public видны только методы ISerializable и всё.

То есть для программиста он останется таким же ISerializable, за исключением того, что QueryInterface иначе далать надо, а для С++ это будет просто NVI view на интерфейс, но это будет спрятано за protected