Изменение прототипа вирт ф-ции в базовом классе
От: Аноним  
Дата: 08.12.05 12:36
Оценка:
Наступил давеча на такие грабли. В базовом классе объявлена вирт. ф-ция, которая понятно переопределяется в наследуемых классах. Схема наследования такая:



class Base { virtual foo() = 0; }
   
   
class Derived : public Base { virtual foo() {}; }
   
   
class Derived1, Derived2, ..., DerivedN : public Derived ;


Основная масса классов пользуется ф-цией, определенной в Derived, но в некоторых из DerivedX требуется переопределять ф-цию foo() специфичным образом. В один прекрасный момент понадобилось изменить прототип ф-ции foo() в классе Base, что и было успешно сделано. Прототип в Derived тоже был изменен ( забыть об этом было нельзя, т.к. foo() в Base чисто виртуальная), а вот про некоторые из классов DerivedX благополучно было забыто (т.к.их достаточно много). Вопрос в том, как писать безопасный код, гарантированно исключающий такие ситуации?
Re: Изменение прототипа вирт ф-ции в базовом классе
От: Lorenzo_LAMAS  
Дата: 08.12.05 12:50
Оценка:
В принципе, в таком случае может помочь компилятор — ворнингами. Но не все компиляторы так могут. Вот g++ предупреждает, что виртуальная функция была скрыта, а не переопределена (не знаю, всегда ли он просекает такое)
Of course, the code must be complete enough to compile and link.
Re: Изменение прототипа вирт ф-ции в базовом классе
От: remark Россия http://www.1024cores.net/
Дата: 08.12.05 14:03
Оценка: 7 (1)
Здравствуйте, Аноним, Вы писали:

А>Наступил давеча на такие грабли. В базовом классе объявлена вирт. ф-ция, которая понятно переопределяется в наследуемых классах. Схема наследования такая:



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


Решение 1 (в лоб):

struct A
{
    virtual void func()
    {
        // Implementation
    }
};

struct B : A
{
    virtual void func()
    {
        if (false) A::func();

        // Implementation
    }
};


Плохо то, что при изменении типа параметра функции на приводимый к исходному работать не будет (например, int изменяем на char, хотя может быть варнинг).


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Изменение прототипа вирт ф-ции в базовом классе
От: remark Россия http://www.1024cores.net/
Дата: 08.12.05 14:12
Оценка: 11 (2)
Здравствуйте, remark, Вы писали:

Улучшенная версия:

struct B : A
{
    virtual void func()
    {
        void (A::*pFunc)() = A::func; pFunc;

        // Implementation
    }
};



R>


1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Изменение прототипа вирт ф-ции в базовом классе
От: Аноним  
Дата: 08.12.05 14:21
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>В принципе, в таком случае может помочь компилятор — ворнингами. Но не все компиляторы так могут. Вот g++ предупреждает, что виртуальная функция была скрыта, а не переопределена (не знаю, всегда ли он просекает такое)



Уродский VC даже варнинга не выдал
Re: Изменение прототипа вирт ф-ции в базовом классе
От: Bell Россия  
Дата: 08.12.05 14:28
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Вопрос в том, как писать безопасный код, гарантированно исключающий такие ситуации?

Увы и ах — на текущий момент "нормального" решения нет. Именно из-за этой проблемы предлагается ввести с С++ новое ключевое слово "override". Не уверен, но по-моему где-то на форуме упоминалось о том, что в VC2005 это ключевое слово есть...
Еще некоторые компиляторы (Comeau например) выдают по такому поводу предупреждение:


#include <iostream>

using namespace std;

struct base
{
   virtual void f(int n) = 0;
   virtual ~base() {}
};

class d1 : public base
{
   virtual void f(int n) { cout << "d1\n"; }
};

class d2 : public d1
{
   virtual void f() { cout << "d2\n"; }
};

int main()
{
    return 0;
}



"ComeauTest.c", line 18: warning: function "base::f(int)" is hidden by "d2::f" --
virtual function override intended?
virtual void f() { cout << "d2\n"; }

Любите книгу — источник знаний (с) М.Горький
Re: Изменение прототипа вирт ф-ции в базовом классе
От: remark Россия http://www.1024cores.net/
Дата: 08.12.05 15:11
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Наступил давеча на такие грабли. В базовом классе объявлена вирт. ф-ция, которая понятно переопределяется в наследуемых классах. Схема наследования такая:



Вариант 2 (как плюс ещё получаем большую гибкость и лучший дизайн):

struct A2
{
    void func()
    {
        core_func();
    }

private:
    virtual void core_func() = 0;
};

struct B2 : A2
{
private:
    virtual void core_func()
    {
        // Implementation
    }
};



Правда в Вашем случае (если у Вас надо полностью перекрывать поведение) прямо так не получиться — надо немного модифицировать.

Вобщем смысл в том, что бы была чисто виртуальная функция


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[2]: Изменение прототипа вирт ф-ции в базовом классе
От: remark Россия http://www.1024cores.net/
Дата: 08.12.05 15:17
Оценка:
Здравствуйте, Bell, Вы писали:

B>Здравствуйте, Аноним, Вы писали:


А>>Вопрос в том, как писать безопасный код, гарантированно исключающий такие ситуации?

B>Увы и ах — на текущий момент "нормального" решения нет. Именно из-за этой проблемы предлагается ввести с С++ новое ключевое слово "override". Не уверен, но по-моему где-то на форуме упоминалось о том, что в VC2005 это ключевое слово есть...
B>Еще некоторые компиляторы (Comeau например) выдают по такому поводу предупреждение:


Предупреждение будет только если изменились параметры, а если изменилось название, то не будет никаких варнингов.

Как нет решения? Я два привёл они, несомненно, менее элегантные, что поддержка со стороны языка, но в жизни применять можно.


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Изменение прототипа вирт ф-ции в базовом классе
От: Павел Кузнецов  
Дата: 09.12.05 05:12
Оценка: 68 (9)
> Основная масса классов пользуется ф-цией, определенной в Derived, но в некоторых из DerivedX требуется переопределять ф-цию foo() специфичным образом. В один прекрасный момент понадобилось изменить прототип ф-ции foo() в классе Base, что и было успешно сделано. Прототип в Derived тоже был изменен ( забыть об этом было нельзя, т.к. foo() в Base чисто виртуальная), а вот про некоторые из классов DerivedX благополучно было забыто (т.к.их достаточно много). Вопрос в том, как писать безопасный код, гарантированно исключающий такие ситуации?

http://tydbits.org/blog/pavel/entry/break_override
Posted via RSDN NNTP Server 2.0
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: Изменение прототипа вирт ф-ции в базовом классе
От: sergey_shandar США http://getboost.codeplex.com/
Дата: 09.12.05 06:24
Оценка:
Здравствуйте, remark, Вы писали:

R>        void (A::*pFunc)() = A::func; pFunc;

Интересная идея. Как развтие темы, можно такой злой макрос написать:
template<class Result, class Base, class Member, Member M>
class override_result
{
public:
    typedef Result type;
};

#define OVERRIDE(RESULT, BASE, NAME, ARGS) \
    override_result<RESULT, BASE, RESULT (BASE::*) ARGS, &BASE::NAME>::type NAME ARGS


И пример его использование:
class Base
{
public:
    virtual int Function(int, const char &) const { return 0; }
};

class Derived: public Base
{
public:
    OVERRIDE(int, Base, Function, (int P, const char &A) const)
    {
        return P + A;
    }
};
getboost.codeplex.com
citylizard.codeplex.com
Re[4]: Изменение прототипа вирт ф-ции в базовом классе
От: _Winnie Россия C++.freerun
Дата: 09.12.05 12:03
Оценка:
Здравствуйте, sergey_shandar, Вы писали:

Как фсё сложно...

#ifdef  _MSC_VER
#  if _MSC_VER >= 1400
#    define OVERRIDE override
#  else
#    define OVERRIDE 
#  endif
#endif


Это во-первых. Во-вторых,


class A
{
public:
    virtual void f() = 0;
    virtual ~A() {}
};

class B: A
{
    virtual void f() const = 0;
};


warning C4263: 'void B::f(void) const' : member function does not override any base class virtual member function
warning C4264: 'void A::f(void)' : no override available for virtual member function from base 'A'; function is hidden

Господа, не выключайте варнинги своего компилятора!
Правильно работающая программа — просто частный случай Undefined Behavior
Re[5]: Изменение прототипа вирт ф-ции в базовом классе
От: Bell Россия  
Дата: 09.12.05 12:28
Оценка: +1
Здравствуйте, _Winnie, Вы писали:

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


_W>Как фсё сложно...


_W>
_W>#ifdef  _MSC_VER
_W>#  if _MSC_VER >= 1400
_W>#    define OVERRIDE override
_W>#  else
_W>#    define OVERRIDE 
_W>#  endif
_W>#endif
_W>


_W>Это во-первых.


К сожалению, далеко не все являются счастливыми обладателями компилятора _MSC_VER >= 1400

_W>Во-вторых,


_W>warning C4263: 'void B::f(void) const' : member function does not override any base class virtual member function

_W>warning C4264: 'void A::f(void)' : no override available for virtual member function from base 'A'; function is hidden

_W>Господа, не выключайте варнинги своего компилятора!

Мне кажется, тут нужно немного перефразировать: "Господа, включайте все варнинги своего компилятора, которые отключены по умолчанию!" Ибо в VC7.1 C4263 и C4264 off by default
Любите книгу — источник знаний (с) М.Горький
Re[2]: Изменение прототипа вирт ф-ции в базовом классе
От: Pavel Chikulaev Россия  
Дата: 09.12.05 12:47
Оценка:
Здравствуйте, Bell, Вы писали:

B>Увы и ах — на текущий момент "нормального" решения нет. Именно из-за этой проблемы предлагается ввести с С++ новое ключевое слово "override". Не уверен, но по-моему где-то на форуме упоминалось о том, что в VC2005 это ключевое слово есть...

Эт из С++/CLI (19.4.1 Draft 1.15) Но туда зачем-то всунули name overriding Еще в Desing & Evolution C++ Bjarne Stroustrup писал какая это глупая идея и почему... (ссылки нет).
ref struct B 
{
    virtual void F() {}
    virtual void F(int i) {}
};

ref struct D1: B 
{
    virtual void F() override {} // explicitly overrides B::F()
};

ref struct D2: B 
{
    virtual void F() override {} // explicitly overrides B::F()
    virtual void G(int i) = B::F {} // named override of B::F(int)
};

ref struct D3: B 
{
    virtual void F() new = B::F {} // named override of B::F()
};


Однако согласно С++/CLI Draft 1.15 20.1

A virtual member function declaration in a native class can contain:

Но нет override... Почему не ясно... Хотя Visual C++ 8.0 компилирует это:
struct A
{
    virtual void f();
};

struct B : A
{
    virtual void f() override;
};


И в MSDN явно написано, что для native классов можно применять override specifiers (new, abstract, override, sealed).
Самое плохое что стандарт ECMA C++/CLI будет принят в этом месяце
Опять несоответствие стандартов и реализаций...
Draft ECMA C++/CLI брать тут. Но сегодня у них какие-то проблемы с сайтом.
Re: Изменение прототипа вирт ф-ции в базовом классе
От: Chez Россия  
Дата: 09.12.05 13:32
Оценка:
Здравствуйте, <Аноним>, Вы писали:

Вот так тоже можно:
class Base
{
    virtual void foo() = 0;
};

class Derived : public Base
{
    virtual void Base::foo() {}
};

class DerivedN : public Derived
{
};

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[2]: Изменение прототипа вирт ф-ции в базовом классе
От: Chez Россия  
Дата: 09.12.05 13:40
Оценка:
Здравствуйте, Chez, Вы писали:

Точнее
class Base
{
    virtual void foo() = 0;
};

class Derived : public Base
{
    virtual void foo() {}
};

class DerivedN : public Derived
{
    virtual void Base::foo() {}
};

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[3]: Изменение прототипа вирт ф-ции в базовом классе
От: Lorenzo_LAMAS  
Дата: 09.12.05 13:41
Оценка:
Извините, ЧОООО ???
Of course, the code must be complete enough to compile and link.
Re[4]: Изменение прототипа вирт ф-ции в базовом классе
От: Chez Россия  
Дата: 09.12.05 14:06
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:

L_L>Извините, ЧОООО ???

Оно самое.
Запустите и увидите.

Chez, ICQ#161095094

Posted via:RSDN@Home;version:1.1.3;muzikstamp:silent

Re[5]: Изменение прототипа вирт ф-ции в базовом классе
От: Lorenzo_LAMAS  
Дата: 09.12.05 14:07
Оценка:
Компилятор какого языка мне надо использовать?
Of course, the code must be complete enough to compile and link.
Re[5]: Изменение прототипа вирт ф-ции в базовом классе
От: Bell Россия  
Дата: 09.12.05 14:07
Оценка:
Здравствуйте, Chez, Вы писали:

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


L_L>>Извините, ЧОООО ???

C>Оно самое.
C>Запустите и увидите.


"ComeauTest.c", line 15: error: qualified name is not allowed
virtual void Base::foo() {}
^

1 error detected in the compilation of "ComeauTest.c".

Любите книгу — источник знаний (с) М.Горький
Re[6]: Изменение прототипа вирт ф-ции в базовом классе
От: Lorenzo_LAMAS  
Дата: 09.12.05 14:09
Оценка:
Дак даже VC 6.0 скажет

D:\test\main.cpp(13) : error C2838: illegal qualified name in member declaration

Of course, the code must be complete enough to compile and link.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.