Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Abyx Россия  
Дата: 09.07.13 09:56
Оценка:
Здравствуйте, Кодт, Вы писали:

К>#if your compiler is not C++11 compliant or not VC2008+

VC2005+
In Zen We Trust
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Erop Россия  
Дата: 09.07.13 10:17
Оценка:
Здравствуйте, VladEC, Вы писали:

VEC>Да, на таком варианте и остановились.

VEC>Изначально не хотели делать "масло масляное", т.к. очевидно, что IWriter::SetPosition() управляет курсором по записи, а IReader::SetPosition() — по чтению.

Можно сделать набор перегруженных функций
void SetPosition( IReader*, int newPos );
void SetPosition( IWriter*, int newPos );
void SetPosition( IStorage*, int newPos );
в которых уже нужные методы и звать, а в коде использовать толкьо редиректоры.
Методы, кстати, можно сделать приватными, а редиректоры -- друзьямИ, но я бы такой ерундой страдать не стал.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 09.07.13 11:16
Оценка:
Здравствуйте, B0FEE664, Вы писали:

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

BFE>А вообще, я плохо понял, что вам надо.

В данном конкретном случае хотелось иметь возможность раздельного управления курсорами через соответствующие интерфейсы: IReader::SetPosition() и IWriter::SetPosition() (both bidirectional & unidirectional storages), т.е. по необходимости предоставлять раздельные реализации методов с совпадающими сигнатурами, но принадлежащих различным интерфейсам.
Соответственно, рассчитывали на то, что наследование различных интерфейсов предполагает (допускает) различные реализации методов (не все стандарт, как отче наш знают, да).

Уже понятно стало, что без бубна (aka прокси или перенаправления вызовов) в обычном C++ так сделать нельзя, т.ч. вопрос закрыт.
Если бы использовался только MSVC, можно было использовать ключевое слово __interface и радоваться, но нужен "глубоко" портируемый код.
Re[6]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 09.07.13 11:58
Оценка: +1 :)
Здравствуйте, VladEC, Вы писали:

VEC>Команда в отпусках почти вся, т.ч. отходить от Coding Conventions в одно лицо нельзя, придется переименовывать.


Вот радости-то будет вернувшимся из отпуска — интерфейсы изменились, зато конвенции соблюдены
Перекуём баги на фичи!
Re[6]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 09.07.13 12:00
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

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

<>

А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?
Это что, приглашение убивать объект через любую его рукоятку?
Перекуём баги на фичи!
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: B0FEE664  
Дата: 09.07.13 12:24
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?

К>Это что, приглашение убивать объект через любую его рукоятку?

да
И каждый день — без права на ошибку...
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 09.07.13 12:38
Оценка:
К>А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?
К>Это что, приглашение убивать объект через любую его рукоятку?

Грубо говоря, да.
Объяснять долго, но так надо
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 09.07.13 12:40
Оценка:
Здравствуйте, Кодт, Вы писали:
VEC>>Команда в отпусках почти вся, т.ч. отходить от Coding Conventions в одно лицо нельзя, придется переименовывать.
К>Вот радости-то будет вернувшимся из отпуска — интерфейсы изменились, зато конвенции соблюдены

В данном случае все правильно.
Единый стиль стоит выше имен отдельных методов. Согласовано с оставшимися в строю.
Re[8]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: VladEC  
Дата: 09.07.13 12:45
Оценка:
Здравствуйте, Erop, Вы писали:

VEC>>Да, на таком варианте и остановились.

VEC>>Изначально не хотели делать "масло масляное", т.к. очевидно, что IWriter::SetPosition() управляет курсором по записи, а IReader::SetPosition() — по чтению.
E>Можно сделать набор перегруженных функций
void SetPosition( IReader*, int newPos );
E>void SetPosition( IWriter*, int newPos );
E>void SetPosition( IStorage*, int newPos );
в которых уже нужные методы и звать, а в коде использовать толкьо редиректоры.

E>Методы, кстати, можно сделать приватными, а редиректоры -- друзьямИ, но я бы такой ерундой страдать не стал.

Да много чего мжно сделать. Но это все выходит за рамки java-style с мульти-интефрейсами, который хотелось использовать изначально.
Т.ч. просто решили не заводить "пересекающихся" имен тем более, что владельцы кода — мы.
К чужому коду в подобной ситуации придется прикручивать костыли, т.ч. все это обсуждение в любом случае не канет в Лету.
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: B0FEE664  
Дата: 09.07.13 12:52
Оценка:
Здравствуйте, VladEC, Вы писали:

VEC>В данном конкретном случае хотелось иметь возможность раздельного управления курсорами через соответствующие интерфейсы: IReader::SetPosition() и IWriter::SetPosition() (both bidirectional & unidirectional storages), т.е. по необходимости предоставлять раздельные реализации методов с совпадающими сигнатурами, но принадлежащих различным интерфейсам.

Раздельные реализации предполагают раздельные типы при сохранении одних и тех же сигнатур.

VEC>Соответственно, рассчитывали на то, что наследование различных интерфейсов предполагает (допускает) различные реализации методов (не все стандарт, как отче наш знают, да).

VEC>Уже понятно стало, что без бубна (aka прокси или перенаправления вызовов) в обычном C++ так сделать нельзя, т.ч. вопрос закрыт.
VEC>Если бы использовался только MSVC, можно было использовать ключевое слово __interface и радоваться, но нужен "глубоко" портируемый код.

не вижу в этом ничего невозможного:
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() {}
};

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

    //make it private:
    int m_pos;
};


int IWriterImpl::Write(const void* buf, size_t& size) { return  0;}
int IWriterImpl::SetPosition(size_t pos)        { m_pos = (int)pos; return m_pos;}

class IReaderImpl : public IReader
{
public:
    virtual int Read(void* buf, size_t& size);
    virtual int SetPosition(size_t pos);
    virtual ~IReaderImpl() {}
    
    //make it private:
    int m_pos;
};


int IReaderImpl::Read(void* buf, size_t& size) { return  0;}
int IReaderImpl::SetPosition(size_t pos)       { m_pos = (int)pos; return m_pos;}

class IMyBiStorageImpl: public IReaderImpl, public IWriterImpl
{
public:
    virtual ~IMyBiStorageImpl() {}
};


class IMyUniStorageImpl: 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);
    virtual ~IMyUniStorageImpl() {}

    //make it private:
    int m_pos;
};

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

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

int IMyUniStorageImpl::SetPosition(size_t pos)
{
  m_pos = pos; return m_pos;
}

int main()
{
    IMyUniStorageImpl sUni;
    IWriter* wUni = &sUni;
    IReader* rUni = &sUni;
    
    wUni->SetPosition(1);
    wUni->SetPosition(2);

    IMyBiStorageImpl sBi;
    IWriter* wBi = &sBi;
    IReader* rBi = &sBi;
    
    wBi->SetPosition(3);
    wBi->SetPosition(4);
  
    return 0;
}


Или вам ещё нужен IStorage?
И каждый день — без права на ошибку...
Re[8]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 10.07.13 08:23
Оценка: +1
Здравствуйте, B0FEE664, Вы писали:

К>>А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?

К>>Это что, приглашение убивать объект через любую его рукоятку?

BFE>да


А не страшно?
Обычно люди как-то жёстче относятся к политикам владения.
Либо — кто создал конкретный объект (и, соответственно, знает его финальный тип), тот его и убивает, а всем остальным даёт интерфейсы объекта попользоваться на время.
Либо это разделяемое владение, неинтрузивное на shared_ptr (см. выше про финальный тип) или интрузивное на методах addref/release, которые объявлены в интерфейсах, но определены в финальном типе.
Либо, на крайний случай, это эстафета: фабрика создаёт объект и отдаёт его интерфейс, в котором есть ручка для убивания. Но это не очень вяжется с множественностью интерфейсов...
Перекуём баги на фичи!
Re[9]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: B0FEE664  
Дата: 10.07.13 09:46
Оценка:
Здравствуйте, Кодт, Вы писали:

К>>>А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?

К>>>Это что, приглашение убивать объект через любую его рукоятку?
BFE>>да
К>А не страшно?
Это было сделано, чтобы показать на необходимость виртуализации деструкторов, которая у VladEC в исходном посте отсутствует. И только.
И каждый день — без права на ошибку...
Re[10]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Evgeny.Panasyuk Россия  
Дата: 10.07.13 11:22
Оценка:
Здравствуйте, B0FEE664, Вы писали:

К>>>>А вот зачем в интерфейсах объявлен и тривиально определён публичный виртуальный деструктор?

К>>>>Это что, приглашение убивать объект через любую его рукоятку?
BFE>>>да
К>>А не страшно?
BFE>Это было сделано, чтобы показать на необходимость виртуализации деструкторов

В том то и дело, что такой необходимости нет
А есть выбор — virtual или protected. Делая такой выбор программист сообщает свои намерения.

BFE>которая у VladEC в исходном посте отсутствует. И только.


В исходном сообщении они вообще private
Re: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Molchalnik  
Дата: 10.07.13 12:14
Оценка: :)
Здравствуйте, VladEC, Вы писали:


VEC>Есть два базовых класса, методы которых я хочу явно перекрыть в классе-наследнике (различное поведение) + реализовать третье поведение, если вызван метод наследника без явного указания базового интерфейса.


Дружище, я не понял твой код, потому что там объявлены виртуальными функции, которые при таком наследовании никогда не будут перегружены. Соответственно, я плохо понимаю, чего ты хочешь. Поэтому позволь тебе задать уточняющий вопрос в виде кода

Код:

class DbgInher1 {
 public:
  virtual void F() {
    printf("\ninherit 1!!!");
  }
};

class DbgInher2 {
 public:
  virtual void F() {
    printf("\ninherit 2!!!");
  }
};


class DbgInherM : public DbgInher1, public DbgInher2 {
 public:
  virtual void F() {
    printf("\ninherit M!!!");
  }
};

int main(int argc, char *argv[])
{
  DbgInherM a;
  a.DbgInher1::F();
  a.DbgInher2::F();
  a.DbgInherM::F();
  a.F();

  printf("\n\n\n");
}

Результат работы данного кода в консоли:

inherit 1!!!
inherit 2!!!
inherit M!!!
inherit M!!!

При этом если убрать все слова virtual, то поведение кода не изменится, т.к. все три функции ни разу не виртуальны по сути.
Мне показалось, что именно предположение о том, что функции должны перегружатся, запутало тебя.

Правильно ли я понял, что это именно то поведение, которое ты хотел?
Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Molchalnik  
Дата: 10.07.13 12:24
Оценка:
Я не могу понять вот чего (и поэтому не уверен, что понял вопрос правильно): ты оформляешь верхние классы как интерфейсы, но при этом делаешь таким образом, чтобы эти интерфейсы никогда не работали. Т.е. на мой взгляд вообще нет никакого смысла в том, чтобы Storage наследовать от IReader IWriter, не используя виртуального наследования от общего предка. Я бы сделал так:


class ISome {
  virtual int SetPosition(size_t pos) = 0;
  virtual ~ISome() {}
}

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

class IWriter : public virtual ISome
{
virtual int Write(const void* buf, size_t& size) = 0;
virtual ~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);
}


При твоём коде я бы понял, в чём проблема. а так — не понимаю. Есть три разные функции, c общим именем SetPosition, зачем-то объявленные виртуальными. Ты хочешь их вызывать по отдельности — ну так вызывай, кто мешает. В чём вопрос-то?
Re[2]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Evgeny.Panasyuk Россия  
Дата: 10.07.13 12:57
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>Дружище, я не понял твой код, потому что там объявлены виртуальными функции, которые при таком наследовании никогда не будут перегружены.


DbgInherM a;
DbgInher1 &b = a;
b.F();
DbgInher2  &c = a;
c.F();
// output:
inherit M!!!
inherit M!!!

Re[3]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 10.07.13 13:06
Оценка:
Здравствуйте, Molchalnik, Вы писали:

<>

отвечу за топикстартера.
Начнём с того, что вообще забудем про наследование интерфейсов.
Пусть у нас есть некоторый туманный объект, который можно рассматривать как читатель (и применять к нему функции read и seek), а можно как писатель (и, соответственно, применять write и seek).
Так вот, иногда seek читателя и писателя хочется выполняють совместно, а иногда порознь.

Если мы запретим перегрузку имён, то ситуация будет выглядеть так
class Storage
{
private:
  void read();
  void write();

  int seek_reader(int);
  int seek_writer(int);
  int seek_both(int);

  friend class IReader;
  friend class IWriter;
  friend class IStorage;
};

И теперь начинается самое интересное. Интерфейс, скажем, читателя, может работать так или этак
class IReader
{
  Storage* impl;
public:
  IReader(Storage* impl) : impl(impl) {}

  void read() { impl->read(); } // тут без вариантов

  int seek_reader(int p) { impl->seek_reader(p); } // так
  int seek_reader(int p) { impl->seek_both(p);   } // этак
};


Ромбовидное наследование — хоть явное, как у тебя, хоть сведённое к перегрузке имён, как у топикстартера, — это всегда "этак", и нужно потратить определённые усилия и использовать нестандартные расширения компиляторов, чтобы сделать "так".

Если же по умолчанию у нас делается "так" (т.е. если мы с самого начала даём разные имена методам интерфейсов), то из "так" сделать "этак" гораздо проще:
class Storage
{
private:
  void read();
  void write();

  int seek_reader(int p) { return seek_both(p); }
  int seek_writer(int p) { return seek_both(p); }
  int seek_both(int);

  friend class IReader;
  friend class IWriter;
  friend class IStorage;
};
Перекуём баги на фичи!
Re[4]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Molchalnik  
Дата: 10.07.13 13:25
Оценка:
Пффф, пусть использует паттерн "шаблонный метод" : объявит все функции интерфейсов невиртуальными. Методы публичного интерфейса пусть вызывают виртуальные функции.


class IReader {
 public:
  void F() {F_RInternal();}
 protected:
  virtual void F_RInternal() = 0;
};


class IWriter {
 public:
  void F();
 protected:
  virtual void F_WInternal() = 0;
};


class IStorage {
 public:
  void F();
 protected:
  virtual void F_SInternal() = 0;
};


void IWriter::F() {
  F_WInternal();
}

void IStorage::F() {
  F_SInternal();
}
Re[7]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Molchalnik  
Дата: 10.07.13 14:22
Оценка:
O>>Но вообще интересно, это вообще как используют клиентом объекта, как вызываться будет SetPosition для reader и writer — не лучше ли переобозвать методы интерфейса -> SetReaderPosition и SetWriterPosition — в нормальной IDE такой рефакторинг делается 2мя кликами.

VEC>Да, на таком варианте и остановились.

VEC>Изначально не хотели делать "масло масляное", т.к. очевидно, что IWriter::SetPosition() управляет курсором по записи, а IReader::SetPosition() — по чтению.

паттерн "Шаблонная функция" спасёт отцов русской демократии, см. мой предыдущий пост
Re[8]: Перегрузка методов базовых классов при множественном наследовании (msvc)
От: Кодт Россия  
Дата: 10.07.13 14:39
Оценка:
Здравствуйте, Molchalnik, Вы писали:

M>паттерн "Шаблонная функция" спасёт отцов русской демократии, см. мой предыдущий пост


Паттерн "переименовать методы" спасёт отцов русской демократии ещё быстрее.
Шаблонная функция противоречит стилю кодирования в компании автора.
Перекуём баги на фичи!
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.