Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 05.07.13 17:49
Оценка: -3
Здравствуйте все!
При попытке скомпилировать под Win32 код, который успешно собирается gcc и clang-ом под Linux, Android, MacOS X и iPhone OS вылезла ошибка, решить которую сходу (красиво!) не удается.
Упростил по максимуму, надеюсь, суть проблемы будет понятна.
Есть два базовых класса, методы которых я хочу явно перекрыть в классе-наследнике (различное поведение) + реализовать третье поведение, если вызван метод наследника без явного указания базового интерфейса.
header-file
class IReader
{
virtual int Read(void* buf, size_t& size) = 0;
virtual int SetPosition(size_t pos) = 0;
~IReader() {}
}

class IWriter
{
virtual int Write(const void* buf, size_t& size) = 0;
virtual int SetPosition(size_t pos) = 0;
~IWriter() {}
}

class Storage: public IReader, public IWriter
{
public:
int Read(void* buf, size_t& size);
int Write(const void* buf, size_t& size);
int SetPosition(size_t pos);
}

source-file
int Storage::Read(void* buf, size_t& size)
{return 0;} // here and below are stubs (obviously!)

int Storage::Write(const void* buf, size_t& size)
{return 0;}

int Storage::SetPosition(size_t pos)
{return 0;}

int Storage::IReader::SetPosition(size_t pos)
{return -1;}

int Storage::IWriter::SetPosition(size_t pos)
{return -2;}


POSIX-компиляторы кушают такой код спокойно и без предупреждений, cl выдал ошибку C2509.
При этой ошибке рекомендуют:
1) Не страдать фигней и переименовать методы базовых классов (не хочу вносить избыточность в имя метода, который может использоваться безотносительно данного наслединка)
2) Вместо class использовать ключевое слово __interface для базовых классов (не получается: в __interface нельзя объявлять вложенные классы, что мне необходимо)
3) Включить перекрываемые методы как inline, т.е. описать прямо в заголовке наследника. Если длинные — использовать перенаправление на функции с отличающимися именами, определить которые можно уже в cpp-файле.

Третий вариант выглядит жизнеспособно, но применять его не очень хочется. Кому-нибудь удавалось собирать подобный код без плясок с бубном?
Или, может, есть еще варианты подобных перекрытий?
NOTE: перефигачить архитектуру не предлагать
Re: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Erop Россия  
Дата: 05.07.13 19:41
Оценка: 6 (2)
Здравствуйте, VladEC, Вы писали:

VEC>Здравствуйте все!


VEC>NOTE: перефигачить архитектуру не предлагать


Как вариант -- выпрямить руки...

Если честно, то я не понял что тебе хотелось выразить. Если оставаться в стандартном С++ без сяких расширений разных, то таки определение виртуальной функции берётся из MDT, даже если виртуальный метод с подходящим прототипом есть в нескольких базах...

То есть твой код не соответствует стандарту С++ и юзает расширение gcc и может ещё чьё-то, а так же дыры в стандарте. Это к вопросу о прямизне рук.

Но, на самом деле даже не особо-то и важно, что там в стандарте написано. Ясно же, что ты юзаешь очень тонкое поведение компилятора. Не можешь ответить за ради чего?
То есть что конкретно ты хотел бы выразить-то?

По поводу не изменения архиитектуры. Что-то же менять всё равно понадобится.
IMHO, проще всего, поменять так. Переименовать все три виртуальные функции, и дополнить классы/интерфейсы NVI.
То есть будет примерно так:
class IReader
{
    virtual int Read(void* buf, size_t& size) = 0;
    int SetPosition(size_t pos) { return setReadPosition( pos ); }
    virtual ~IReader() {}
protected:
    virtual int setReadPosition(size_t pos) = 0;
}

class IWriter
{
    virtual int Write(const void* buf, size_t& size) = 0;
    int SetPosition(size_t pos) { return setWritePosition( pos ); }
    virtual ~IWriter() {}
protected:
    virtual int setWritePosition(size_t pos) = 0;
}

class Storage: public IReader, public IWriter
{
public:
    int Read(void* buf, size_t& size);
    int Write(const void* buf, size_t& size);
    int SetPosition(size_t pos);
protected:
    virtual int setReadPosition(size_t pos);
    virtual int setWritePosition(size_t pos);
}
либо просто переименовать функции в райтере и ридере...
В общем, пока не объяснишь, что тебе на самом деле надо, либо кто-то это не протелепает, совета дельного тебе дать будет непросто
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 06.07.13 18:14
Оценка: 1 (1)
Здравствуйте, VladEC, Вы писали:

VEC>NOTE: перефигачить архитектуру не предлагать


А немножко дофигачивать архитектуру можно?
#if your compiler is not C++11 compliant or not VC2008+
#define abstract = 0
#define final
#define override
#endif

struct IReaderDisambiguated : IReader
{
  virtual int SetPosition(size_t pos) final { return SetReaderPosition(pos); }
  virtual int SetReaderPosition(size_t pos) abstract;
};
struct IWriterDisambiguated : IReader
{
  virtual int SetPosition(size_t pos) final { return SetWriterPosition(pos); }
  virtual int SetWriterPosition(size_t pos) abstract;
};

class Storage : public IReaderDisambiguated, public IWriterDisambiguated
{
  virtual int Read(void* buf, size_t& size) override;
  virtual int Write(const void* buf, size_t& size) override;
  virtual int SetReaderPosition(size_t pos) override;
  virtual int SetWriterPosition(size_t pos) override;
};
Перекуём баги на фичи!
Re: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: enji  
Дата: 07.07.13 11:55
Оценка: 1 (1)
Здравствуйте, VladEC, Вы писали:

VEC>Здравствуйте все!

VEC>При попытке скомпилировать под Win32 код, который успешно собирается gcc и clang-ом под Linux, Android, MacOS X и iPhone OS вылезла ошибка, решить которую сходу (красиво!) не удается.
VEC>Упростил по максимуму, надеюсь, суть проблемы будет понятна.
VEC>Есть два базовых класса, методы которых я хочу явно перекрыть в классе-наследнике (различное поведение) + реализовать третье поведение, если вызван метод наследника без явного указания базового интерфейса.
VEC>header-file
VEC>
VEC>class IReader
VEC>{
VEC>virtual int Read(void* buf, size_t& size) = 0;
VEC>virtual int SetPosition(size_t pos) = 0;
VEC>~IReader() {}
VEC>}

VEC>class IWriter
VEC>{
VEC>virtual int Write(const void* buf, size_t& size) = 0;
VEC>virtual int SetPosition(size_t pos) = 0;
VEC>~IWriter() {}
VEC>}

struct Storage_IReader : IReader {
  inline int SetPosition(size_t pos);
};

struct Storage_IWriter : IWriter{
  inline int SetPosition(size_t pos);
};

VEC>class Storage: public Storage_IReader , public Storage_IWriter 
VEC>{
VEC>public:
VEC>int Read(void* buf, size_t& size);
VEC>int Write(const void* buf, size_t& size);
VEC>int SetPosition_read(size_t pos);
    int SetPosition_write(size_t pos);
VEC>}

int Storage_IReader::SetPosition(size_t pos) { return  static_cast<Storage*>(this)->setPosition_read(pos); }
VEC>
Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 11:23
Оценка:
Здравствуйте, Кодт, Вы писали:

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


VEC>>NOTE: перефигачить архитектуру не предлагать


К>А немножко дофигачивать архитектуру можно?


Ну это как бы первый вариант — переименовать методы базовых классов.
Мы сейчас к нему и придем, похоже, потому что gcc 4.7 выдал ошибки линковки, возиться с которыми уже не будем. Вылезло один раз и не на cl, значит, может вылезти еще.
Каждый раз костыли вставлять бессмысленно.
Re[3]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 08.07.13 11:34
Оценка:
Здравствуйте, VladEC, Вы писали:

К>>А немножко дофигачивать архитектуру можно?

VEC>Ну это как бы первый вариант — переименовать методы базовых классов.

Это, как бы, полуторный: интерфейсы оставить как есть, но ввести прослойки.
Перекуём баги на фичи!
Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 11:50
Оценка:
Здравствуйте, Erop, Вы писали:

VEC>>NOTE: перефигачить архитектуру не предлагать

E>Как вариант -- выпрямить руки...

Ну да, всей команде

E>Если честно, то я не понял что тебе хотелось выразить. Если оставаться в стандартном С++ без сяких расширений разных, то таки определение виртуальной функции берётся из MDT, даже если виртуальный метод с подходящим прототипом есть в нескольких базах...


Есть оъекты, работающие по отдельности с интерфейсами IReader и IWriter. Есть объект с интерфейсом IStorage (и запись, и чтение), который можно передать этим объектам (помимо объектов с интерфейсами IReader/IWriter). Была идея сделать "красиво": при обращении к объекту Storage указанием на конкретный интерфейс (IReader/IWriter) задавать, какую именно позицию меняет вызывающий код (по чтению или записи), или и вовсе перекрыть оба SetPosition в самом Storage, если раздельное управление курсором не поддерживается в данном объекте.
Имя функции SetPosition() при этом не избыточное, то есть мы не говорим, что в объекте Writer оно управляет курсором по записи, в Reader — по чтению.

E>По поводу не изменения архиитектуры. Что-то же менять всё равно понадобится.


На данный момент отказались от "красивой" идеи, пришли к "избыточности имен".
У нас в Coding Conventions ограничение: в заголовках, описывающих интефрейсы, не определять непустые функции (т.е. только деструктор виртуальный вставляется).
Т.ч. Ваше решение красивое (и схоже с 3-м вариантом из моих, где в объявление инлайнятся определения перекрываемых методов), но не подходит.

В любом случае спасибо за внимание и идею!

P.S. Загадочность вопросов прямо пропорциональная кривизне рук, кривизна рук прямо пропорциональна размеру команды и стремлению сделать "красиво"
Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 11:53
Оценка:
Здравствуйте, enji, Вы писали:
E>int Storage_IReader::SetPosition(size_t pos) { return static_cast<Storage*>(this)->setPosition_read(pos); }
VEC>>[/ccode]

Жуть какая
Вариант с инлайном в базовых IReader/IWriter (приведенный выше) мне больше понравился
Но спасибо!
Re[4]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 11:57
Оценка:
Здравствуйте, Кодт, Вы писали:

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


К>>>А немножко дофигачивать архитектуру можно?

VEC>>Ну это как бы первый вариант — переименовать методы базовых классов.

К>Это, как бы, полуторный: интерфейсы оставить как есть, но ввести прослойки.


Суть идеи была в том, чтобы в Storage можно было управлять общим курсором через SetPosition, а не SetReadPosition/SetWritePosition.
Признаюсь, не сразу увидел, что Вы предлагаете унаследоваться от IReader/IWriter в промежуточных классах.
Для нас тут одна засада: мы в интерфейсах договорились определений функций не создавать.
Re[3]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: enji  
Дата: 08.07.13 12:32
Оценка:
Здравствуйте, VladEC, Вы писали:

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

E>>int Storage_IReader::SetPosition(size_t pos) { return static_cast<Storage*>(this)->setPosition_read(pos); }
VEC>>>[/ccode]

VEC>Жуть какая

Чего ж тут такого жуткого? Обычный передаточный метод, после встраивания накладных расходов не будет.
VEC>Вариант с инлайном в базовых IReader/IWriter (приведенный выше) мне больше понравился
А что за метод такой и чем он тебе может помочь? Насколько я понимаю, в плюсах нельзя указать, метод какого класса ты перекрываешь, так что если у тебя в базовых классах совпадают названия и сигнатуры виртуальных методов, то решения два — или (как тебе сказал Егор выше) NVI или прокси (у меня — статический, у Кодта — динамический)
Re[4]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 13:00
Оценка:
Здравствуйте, enji, Вы писали:

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


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

E>>>int Storage_IReader::SetPosition(size_t pos) { return static_cast<Storage*>(this)->setPosition_read(pos); }

VEC>>Жуть какая

E>Чего ж тут такого жуткого? Обычный передаточный метод, после встраивания накладных расходов не будет.

VEC>>Вариант с инлайном в базовых IReader/IWriter (приведенный выше) мне больше понравился

E>А что за метод такой и чем он тебе может помочь? Насколько я понимаю, в плюсах нельзя указать, метод какого класса ты перекрываешь, так что если у тебя в базовых классах совпадают названия и сигнатуры виртуальных методов, то решения два — или (как тебе сказал Егор выше) NVI или прокси (у меня — статический, у Кодта — динамический)

Тот, который NVI, удобен. Схожий метод я рассматривал с самого начала под п.3
Нарыл его где-то на просторах IBM или MSDN, не вспомню.
От реализации Кодта принципиальных отличий в Вашем решении не вижу, если честно: и там, и там вводится промежуточный класс (прокси), который перенаправляет вызовы к закрытой/защищенной функции, реализация которой отличается. Не углубляясь в подробности нашего решения, несмотря на годность ответа к заданному вопросу, подобный метод не совсем подходит.
Ничем не хуже выглядит определить в заголовке inline-методы IReader::SetPosition/IWriter::SetPosition, перенаправляющие вызов на конкретные закрытые реализации, в самом Storage (п.3).

Уже нарыли сами тут, что стандарт действительно не поддерживает желаемого изначально извращения, т.ч. пришлось-таки "перефигачивать" немножко.
Заметным ограничением выступает Coding Style/Guidelines, принятый командой, — не определять функций в объявлениях интерфейсов (в заголовках, впрочем, тоже).
Re[5]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: B0FEE664  
Дата: 08.07.13 13:10
Оценка:
Здравствуйте, VladEC, Вы писали:

VEC>Суть идеи была в том, чтобы в Storage можно было управлять общим курсором через SetPosition, а не SetReadPosition/SetWritePosition.


В таком случае надо убрать вредное final из IReaderDisambiguated и IWriterDisambiguated и перекрыть SetPosition(size_t pos) в тех Storage, которые не поддерживают раздельное позиционирование.

VEC>Признаюсь, не сразу увидел, что Вы предлагаете унаследоваться от IReader/IWriter в промежуточных классах.

VEC>Для нас тут одна засада: мы в интерфейсах договорились определений функций не создавать.

Мне любопытно: чем вызвано столь странное ограничение?
И каждый день — без права на ошибку...
Re[4]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 13:11
Оценка:
Здравствуйте, Кодт, Вы писали:

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


К>>>А немножко дофигачивать архитектуру можно?

VEC>>Ну это как бы первый вариант — переименовать методы базовых классов.
К>Это, как бы, полуторный: интерфейсы оставить как есть, но ввести прослойки.

Еще раз посмотрел ВНИМАТЕЛЬНО , это даже ближе к 3-му решению из моих: добавить перенаправление вызовов в заголовок.
Только у меня inline-методы предусматривались, а у Вас промежуточные классы.
Т.е. мой вариант был такой (надо было привести, конечно)
class Storage: public IWriter, public IReader
{
public:
    inline int IWriter::SetPosition(size_t pos){return SetWritePosition(size_t pos);} 
    inline int IReader::SetPosition(size_t pos){return SetReadPosition(size_t pos);} 
// skipped
protected:
    int SetWritePosition(size_t pos);
    int SetReadPosition(size_t pos);
}


Оно, насколько мне известно, компилируется и работает.

Кстати, я в процессе упрощения кода для примера не упомянул, что над Storage у нас интерфейс IStorage: public IReader, public IWriter, т.ч. получится крокодил...
IReader                IWriter
   |                      |
IReaderDisambiguated   IWriterDisambiguated
                  \      /
                  IStorage
                     |
                  Storage
Re[6]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 13:19
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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


VEC>>Суть идеи была в том, чтобы в Storage можно было управлять общим курсором через SetPosition, а не SetReadPosition/SetWritePosition.

BFE>В таком случае надо убрать вредное final из IReaderDisambiguated и IWriterDisambiguated и перекрыть SetPosition(size_t pos) в тех Storage, которые не поддерживают раздельное позиционирование.

Да, варианты есть. Я чуть ниже Вашего комментария привел пример, как обойтись без промежуточных классов.

VEC>>Признаюсь, не сразу увидел, что Вы предлагаете унаследоваться от IReader/IWriter в промежуточных классах.

VEC>>Для нас тут одна засада: мы в интерфейсах договорились определений функций не создавать.

BFE>Мне любопытно: чем вызвано столь странное ограничение?


Мне тоже, но не я его придумал
Аргумент, который я слышал: не мешать в кучу объявления и определения, определения всегда ищутся в исходнике (сложно определить однозначно, код какого объема можно объявить в заголовке, а какой код надо помещать в исходник). Ну а интерфейсы вообще должны быть абстрактными без определений (java-style).
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 08.07.13 13:54
Оценка:
Здравствуйте, VladEC, Вы писали:

VEC>Аргумент, который я слышал: не мешать в кучу объявления и определения, определения всегда ищутся в исходнике (сложно определить однозначно, код какого объема можно объявить в заголовке, а какой код надо помещать в исходник). Ну а интерфейсы вообще должны быть абстрактными без определений (java-style).


Так IxxxxDisambiguated — не интерфейсы, а просто абстрактные классы. Для внутреннего использования.
Или у вас иерархия строго двухуровневая: базы — только интерфейсы, реализации — только запаянные?

Другое дело, что в ява-стиле нет множественного наследования...
Перекуём баги на фичи!
Re[8]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 14:01
Оценка:
Здравствуйте, Кодт, Вы писали:

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


VEC>>Аргумент, который я слышал: не мешать в кучу объявления и определения, определения всегда ищутся в исходнике (сложно определить однозначно, код какого объема можно объявить в заголовке, а какой код надо помещать в исходник). Ну а интерфейсы вообще должны быть абстрактными без определений (java-style).


К>Так IxxxxDisambiguated — не интерфейсы, а просто абстрактные классы. Для внутреннего использования.

К>Или у вас иерархия строго двухуровневая: базы — только интерфейсы, реализации — только запаянные?

Я тут чуть выше схему, которая ближе к реальности, привел, в ней Storage — не класс, а интерфейс (IStorage), соответственно, IxxxDisambiguated начинают "торчать" в интерфейсе.

К>Другое дело, что в ява-стиле нет множественного наследования...


В ява как раз есть множественное наследование интерфейсов, чего нам тут не хватило.
Проблема вылезла из-за того, что в С++ не поддерживается (без бубна) наследование разных интерфейсов, в которых совпадают названия и сигнатуры методов.
Если бы мы не являлись владельцами кода, действительно не обошлось бы без middleware
Re[5]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 08.07.13 14:44
Оценка:
К>>>>А немножко дофигачивать архитектуру можно?
VEC>>>Ну это как бы первый вариант — переименовать методы базовых классов.
К>>Это, как бы, полуторный: интерфейсы оставить как есть, но ввести прослойки.

VEC>Еще раз посмотрел ВНИМАТЕЛЬНО , это даже ближе к 3-му решению из моих: добавить перенаправление вызовов в заголовок.

VEC>Только у меня inline-методы предусматривались, а у Вас промежуточные классы.
VEC>Т.е. мой вариант был такой (надо было привести, конечно)
VEC>
VEC>class Storage: public IWriter, public IReader
VEC>{
VEC>public:
VEC>    inline int IWriter::SetPosition(size_t pos){return SetWritePosition(size_t pos);} 
VEC>    inline int IReader::SetPosition(size_t pos){return SetReadPosition(size_t pos);} 
VEC>// skipped
VEC>protected:
VEC>    int SetWritePosition(size_t pos);
VEC>    int SetReadPosition(size_t pos);
VEC>}
VEC>


VEC>Оно, насколько мне известно, компилируется и работает.


Сам себе отвечу...
Проверил все-таки, что пишу
В GCC/CLANG(LLVM) такое не компилируется и не работает. Это был вариант, найденный на StackOverflow для cl.
Так что для сохранения "красивых имен" подходят только прокси-класс или NVI. NVI мне нравится больше, т.к. не плодит сущностей...
Команда в отпусках почти вся, т.ч. отходить от Coding Conventions в одно лицо нельзя, придется переименовывать.

Вообще какая-то загадка. На модельных примерах собираться вся эта ерунда перестала.
Т.ч., видимо, в проекте не только в интерфейсах косяки gcc/clang
Что называется, "найди, почему оно собиралось, когда не должно было". Подозреваю, что до линковки необъявленных методов не доходило — unit test еще не прикрутили даже

Резюме: ВСЕМ помогающим спасибо за умные мысли и дельные советы!
"Минусаторам" вопросов :-P
Попробуйте найти ответ на вопрос "перекрытие методов с совпадающими сигнатурами при множественном невиртуальном наследовании", не погружаясь в стандарт по самые помидоры.
Re[5]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: B0FEE664  
Дата: 08.07.13 16:04
Оценка:
Здравствуйте, VladEC, Вы писали:


VEC>Кстати, я в процессе упрощения кода для примера не упомянул, что над Storage у нас интерфейс IStorage: public IReader, public IWriter, т.ч. получится крокодил...

      IReader     IWriter
           \      /
           IStorage
             |
            Storage



Вот вам как в Java, наследование интерфейсов и реализация:

class IReader
{
public:
    virtual int Read(void* buf, size_t& size) = 0;
    virtual int SetPosition(size_t pos) = 0;
    virtual ~IReader() {}
};

class IWriter
{
public:
    virtual int Write(const void* buf, size_t& size) = 0;
    virtual int SetPosition(size_t pos) = 0;
    virtual ~IWriter() {}
};

//IMyStorage вместо IStorage, потому, что у майкрософта есть свой IStorage 
class IMyStorage: public IReader, public IWriter
{
public:
    virtual int Read(void* buf, size_t& size) = 0;
    virtual int Write(const void* buf, size_t& size) = 0;
    virtual int SetPosition(size_t pos) = 0;
    virtual ~IMyStorage() {}
};

class Storage: public IMyStorage
{
public:
    int Read(void* buf, size_t& size);
    int Write(const void* buf, size_t& size);
    int SetPosition(size_t pos);
    virtual ~Storage() {}
};



int Storage::Read(void* buf, size_t& size)
{
  return 3;
}

int Storage::Write(const void* buf, size_t& size)
{
  return 2;
}


int Storage::SetPosition(size_t pos)
{
  return 1;
}


int main()
{
    Storage s;
    IWriter* w = &s;
    IReader* r = &s;


    std::cout << "Press any key to exit..." << std::endl;
    char ch = _getch();
  
    return 0;
}


А вообще, я плохо понял, что вам надо.
И каждый день — без права на ошибку...
Re[5]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: omgOnoz  
Дата: 09.07.13 01:30
Оценка:
>> Заметным ограничением выступает Coding Style/Guidelines, принятый командой, — не определять функций в объявлениях интерфейсов (в заголовках, впрочем, тоже).
Понятно, закос под Java делаете — где "множественное наследование" только для интерфейсов.

Но вообще интересно, это вообще как используют клиентом объекта, как вызываться будет SetPosition для reader и writer — не лучше ли переобозвать методы интерфейса -> SetReaderPosition и SetWriterPosition — в нормальной IDE такой рефакторинг делается 2мя кликами.
Re[6]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 09.07.13 09:33
Оценка:
Здравствуйте, omgOnoz, Вы писали:

>>> Заметным ограничением выступает Coding Style/Guidelines, принятый командой, — не определять функций в объявлениях интерфейсов (в заголовках, впрочем, тоже).

O>Понятно, закос под Java делаете — где "множественное наследование" только для интерфейсов.

Ну да, так и задумано.
Если есть необходимость сочетать функциональность нескольких классов, они агрегируются, а не наследуются (паттерны proxy, facade и т.п.).

O>Но вообще интересно, это вообще как используют клиентом объекта, как вызываться будет SetPosition для reader и writer — не лучше ли переобозвать методы интерфейса -> SetReaderPosition и SetWriterPosition — в нормальной IDE такой рефакторинг делается 2мя кликами.


Да, на таком варианте и остановились.
Изначально не хотели делать "масло масляное", т.к. очевидно, что IWriter::SetPosition() управляет курсором по записи, а IReader::SetPosition() — по чтению.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.