Алик
Постоялец
Offline
|
|
« : 02-11-2004 11:59 » |
|
Есть два виртуальных класса (имена изменены, любое сходство случайно ) class A{ ... virtual void userproc(int result){}; };
class B{ ... virtual void userproc(int result){}; }; Эти классы что-то вычисляют, и вызывают userproc с результатом вычислений в качестве параметра. потомки классов перекрывают юзерпроки своими полезными процедурами. Теперь появилась нужда в классе class AB:public A,public B{ <виртуальная функция, замещающая A::userproc> <виртуальная функция, замещающая B::userproc> } Это как-нибудь можно реализовать? Что-то я по Страуструпу глазами пробежал - не нашел...
|
|
« Последнее редактирование: 02-12-2007 16:59 от Алексей1153++ »
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #1 : 02-11-2004 12:11 » |
|
не очень понял . может так: class AB:public A,public B { virtual void userprocA(int result) { A::userproc(result); } virtual void userprocB(int result) { B::userproc(result); } };
|
|
« Последнее редактирование: 02-12-2007 17:00 от Алексей1153++ »
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #2 : 02-11-2004 13:59 » |
|
не очень понял . может так: class AB:public A,public B { virtual void userprocA(int result) { A::userproc(result); } virtual void userprocB(int result) { B::userproc(result); } };
нет, так не пойдет. Виртуальные функции вызываются из других методов классов A и B. Что-то типа этого: class A{ virtual void userproc(int result){}; void main(){ ... userproc(15); } } И идея в том, что процедура main должна вызывать AB::<виртуальная функция, замещающая A::userproc>
|
|
« Последнее редактирование: 02-12-2007 17:01 от Алексей1153++ »
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #3 : 02-11-2004 14:22 » |
|
Алик, а для какого объекта, А или АВ? Что то я тебя не понял.
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
npak
|
|
« Ответ #4 : 02-11-2004 14:28 » |
|
Алик, а тебе что надо? Ты словами объясни, без кода. Какую цель ты преследуешь, что хочешь решить?
Может быть тогда найдётся более изящный путь?
|
|
|
Записан
|
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #5 : 02-11-2004 15:12 » |
|
Есть класс, который перебирает все возможные комбинации чисел от 0 до x. Для каждой последовательности вызывается виртуальная процедура void userproc(vector<DWORD>& v) (в векторе - комбинация). В этом классе она ничего не делает и должна быть перекрыта в потомке (и действовать в зависимости от нужд пользователя). И второй класс действует по такому же принципу. Производный класс использует функциональность обоих классов. Вот.
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #6 : 02-11-2004 15:25 » |
|
Алик, что значит "использует" ? Если тебе надо вызывать функции базовых классов, то обращайся к ним как A::userproc и B::userproc Более того, достаточно сделать абстрактный базовый класс и унаследовать A, В и АВ от него. class base_C { public: virtual void userproc(int x) = 0; };
class A : public base_C { public: virtual void userproc(int ); };
class B : public base_C { public: virtual void userproc(int ); };
class C : public base_C { A _a; B _b; public: virtual void userproc(int ); };
void C::userproc(int x) { _a.userproc(x); _b.userproc(x); }
|
|
« Последнее редактирование: 02-12-2007 17:02 от Алексей1153++ »
|
Записан
|
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #7 : 03-11-2004 03:12 » |
|
npak, в твоем коде уже не множественное наследование (вообще не наследование). Я знаю, что есть этот вариант. Но мне интересно, дает ли язык возможность осуществить мой замысел именно через множественное наследование, иначе придется объявлять 2 класса, производных от А и B с перекрытым методом userproc, и уже экземпляры этих классов делать членами класса C, что, на мой взгляд, не очень элегантно.
|
|
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #8 : 03-11-2004 06:39 » |
|
Алик, мдааааааа :new_shot:
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #10 : 03-11-2004 08:04 » |
|
Алик, этой загадочной фразы я просто не понял Есть два виртуальных класса
особенно если после этого следует такой код class A{ ... virtual void userproc(int result){}; };
class B{ ... virtual void userproc(int result){}; };
Идем дальше, ты пишешь Теперь появилась нужда в классе Код: class AB:public A,public B{ <виртуальная функция, замещающая A::userproc> <виртуальная функция, замещающая B::userproc> }
У меня тут вопрос, в класса AB должны быть ДВЕ функции (одна из которых замещаяет A::userproc, а вторая B::userproc) или одна??? вот посмотри сюда может тебе надо это class Abstruct { public: virtual ~Abstruct() {} virtual void f(const char * s) = 0; };
class A : public Abstruct { public: void fa(const char * s) { // ... f(s); } };
class B : public Abstruct { public: void fb(const char * s) { // ... f(s); } };
class AB : public A, public B { public: void f(const char * s) { s = "do something..."; } };
void main() { AB ab; ab.fa("fa"); ab.fb("fb"); }
|
|
« Последнее редактирование: 02-12-2007 17:03 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #11 : 03-11-2004 08:23 » |
|
Алик, этой загадочной фразы я просто не понял Есть два виртуальных класса
особенно если после этого следует такой код class A{ ... virtual void userproc(int result){}; };
class B{ ... virtual void userproc(int result){}; };
Идем дальше, ты пишешь Теперь появилась нужда в классе Код: class AB:public A,public B{ <виртуальная функция, замещающая A::userproc> <виртуальная функция, замещающая B::userproc> }
У меня тут вопрос, в класса AB должны быть ДВЕ функции (одна из которых замещаяет A::userproc, а вторая B::userproc) или одна??? вот посмотри сюда может тебе надо это class Abstruct { public: virtual ~Abstruct() {} virtual void f(const char * s) = 0; };
class A : public Abstruct { public: void fa(const char * s) { // ... f(s); } };
class B : public Abstruct { public: void fb(const char * s) { // ... f(s); } };
class AB : public A, public B { public: void f(const char * s) { s = "do something..."; } };
void main() { AB ab; ab.fa("fa"); ab.fb("fb"); }
Виртуальный класс - класс, имеющий виртуальные методы (то есть, имеющий vtbl). Не путать с виртуальным базовым классом. Что тебе непонятно в моей фразе? Да, мне нужно, чтобы класс потомок имел ДВА метода, каждый из которых перекрывал бы виртуальный метод одного из классов-предков. Единственная загвоздка - эти виртуальные методы имеют одинаковые имена. Как это обойти?
|
|
« Последнее редактирование: 02-12-2007 17:04 от Алексей1153++ »
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #12 : 03-11-2004 08:26 » |
|
lapulya, дело в том что эти функции в А и В НИЧЕГО НЕ ДЕЛАЮТ. Те это просто virtual void userproc(int result) = 0; как я понимаю,(цитата - " В этом классе она ничего не делает и должна быть перекрыта в потомке") а подменить в потомках я не вижу никакой сложности, хоть трижды наследуй. Посему понял что смысл вопроса - сколько будет дважды два четыре. И ответ соответствующий TRUE.
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #13 : 03-11-2004 08:37 » |
|
Таварищи, ну граждане родненькие! ну где дважды два?? Pu, ну напиши код для примера, если все так просто!
|
|
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #14 : 03-11-2004 08:42 » |
|
Алик, Виртуальный класс - класс, имеющий виртуальные методы (то есть, имеющий vtbl).
Это где же ты такое определение увидал то ну а вот так Да, мне нужно, чтобы класс потомок имел ДВА метода, каждый из которых перекрывал бы виртуальный метод одного из классов-предков. Единственная загвоздка - эти виртуальные методы имеют одинаковые имена. Как это обойти?
сделать нельзя! Pu, дело в том что эти функции в А и В НИЧЕГО НЕ ДЕЛАЮТ
Дык!!! они и у меня ничего не делают...вот смотри, функция virtual void f(const char * s) = 0;
объавлена в классе Abstract (это аналог virtual void userproc(int result) = 0; ), а в классе А и В объявление этих функций присутствует только косвенно т.к. они оба наследники австрактного класса Abstract, и естественно ни А ни В не реализуют эту функцию...
|
|
|
Записан
|
С уважением Lapulya
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #15 : 03-11-2004 08:54 » |
|
Это где же ты такое определение увидал то Вроде, у Страуструпа где-то. ну а вот так Да, мне нужно, чтобы класс потомок имел ДВА метода, каждый из которых перекрывал бы виртуальный метод одного из классов-предков. Единственная загвоздка - эти виртуальные методы имеют одинаковые имена. Как это обойти? сделать нельзя! Ну я так и подозревал. Придется изворачиваться... lapulya,Твой пример с классом Abstract делает не то, что мне нужно. Там оба виртуальных метода предков перекрываются одним методом потомка.
|
|
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #16 : 03-11-2004 09:14 » |
|
Алик, а зачем два метода . Ты в одной области видимости НИКОГДА не получишь две функции с одной сигнатурой, к бабке не ходи. может повторюсь уж звиняйте class A { public: int x; A(int v) : x(v) {} virtual void f(int i) = 0; // ничего не делает };
class B { public: int x; B(int v) : x(v) {} virtual void f(int i) = 0; // ничего не делает тоже };
class AB : public A, public B { public: AB( int va, int vb) : A(va), B(vb) {} virtual void f(int i) // делает чтото и закрывает (тоесть вообще) функции в базовых классах , и дает доступ к любым их паблик и протект членам { i = A::x + B::x; } };
int _tmain(int argc, _TCHAR* argv[]) { AB ab(2,3); ab.f( 44); return 0; }
|
|
« Последнее редактирование: 02-12-2007 17:05 от Алексей1153++ »
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #17 : 03-11-2004 09:30 » |
|
Pu, Твой пример делает не то, что мне нужно. Там ОБА виртуальных метода предков перекрываются ОДНИМ методом потомка.
|
|
|
Записан
|
|
|
|
npak
|
|
« Ответ #18 : 03-11-2004 09:36 » |
|
Алик, В С++ есть возможность вызвать метод класса предка. AB ab; ab.A::userproc(1); // Вызов метода предка A ab.B::userproc(2); // Вызов метода предка B
Правильно ли я понимаю, что ты хочешь, чтобы в выражении ab.B::userproc(1) вызывался не тот метод, который определён для класса B, а некоторый другой, переопределённый? Ответ: так нельзя. Квалификация имени специально придумана, чтобы обходить перегрузку имён и вызывать метод предка. Теперь о множественном наследовании. Я не вижу никаких выгод в данном случае. По-моему, агрегация более уместна. Возможно, это убеждение сформировалось у меня после Java, но я стараюсь избегать в С++ множественного наследования.
|
|
« Последнее редактирование: 02-12-2007 17:06 от Алексей1153++ »
|
Записан
|
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #19 : 03-11-2004 09:44 » |
|
npak, Я согласен, что множественное наследование нужно стараться обходить. Но в моем случае методы обоих классов-предков (те самые, перегруженные в потомке) используют одни и те же данные, являющиеся членами класса-потомка. И обеспечить к этим данным доступ в случае агрегации паревно.
|
|
|
Записан
|
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #20 : 03-11-2004 09:56 » |
|
В общем, я эту проблему так решил: class tcombinations{ ... virtual void userproc(const vector<DWORD>& v){}; ...
};
class tsumitems{ ... virtual void userproc(const vector<DWORD>& v){}; ... };
class tsgsumitems:public tsumitems{ void userproc(const vector<DWORD>& v)|si_userproc(v);}; virtual void si_userproc(const vector<DWORD>& v){}; };
class tsgcombinations:public tcombinations{ void userproc(const vector<DWORD>& v)|cb_userproc(v);}; virtual void cb_userproc(const vector<DWORD>& v){}; };
class tsumgroupper:public tsgcombinations,public tsgsumitems{ ... //эти два метода, фактически, перекрывают методы userproc классов tsumitems и tcombinations void si_userproc(const vector<DWORD>& v){ //ду самфин }; void cb_userproc(const vector<DWORD>& v){ //ду самфин элс }; ... };
|
|
« Последнее редактирование: 02-12-2007 17:08 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #21 : 03-11-2004 09:58 » |
|
Алик, class AB { friend class A; friend class B;
A * a; B * b; };
и ни какой парильни...
|
|
« Последнее редактирование: 02-12-2007 17:10 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #22 : 03-11-2004 10:02 » |
|
lapulya А доступ к членам AB?
|
|
|
Записан
|
|
|
|
Pu
Большой босс
Offline
78
|
|
« Ответ #23 : 03-11-2004 10:07 » |
|
Алик, мне почему-то каэться, что у тебя проблемы с проектированием классов, чтобы предки использовали данные потомков . Да они и знать не должны что там у них есть какието производные классы! Изврат, имхо, и полиморфизм вывернутый наизнанку.
|
|
|
Записан
|
Насколько я опытен? Достаточно, чтобы понимать, что дураков нельзя заставить думать по–другому, но недостаточно, чтобы отказаться от попыток это сделать. (с) Артур Джонс
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #24 : 03-11-2004 10:09 » |
|
Алик, ХАХАХАХАХАХАХАХА!!!!!!!!!!!!!!!!!!!!!!! я вот это class A { public: virtual void f(const char * s) = 0; void fa(const char * s) { f(s); } };
class B { public: virtual void f(const char * s) = 0; void fb(const char * s) { f(s); } };
class AA : public A { public: virtual void faa(const char * s) = 0; void f(const char * s) { faa(s); }; };
class BB : public B { public: virtual void fbb(const char * s) = 0; void f(const char * s) { fbb(s); }; };
class AB : public AA, public BB { public: void faa(const char * s) { s = "do something..."; }
void fbb(const char * s) { s = "do something..."; } };
void main() { AB ab; ab.fa("fa"); ab.fb("fb"); }
написал полтора часа назад .... но потом подумал что это полнейший калл и решил что эта писанина не достойна того чтобы на нее смотреть...
|
|
« Последнее редактирование: 02-12-2007 17:11 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
npak
|
|
« Ответ #25 : 03-11-2004 10:14 » |
|
Алик, При множественном наследовании объект включает в себя подобъекты, по одному для каждого класса-предка. Методы классов-предков используют данные, которые приндлежат к под-объектам! Они не имеют доступа к данным объекта! Вот тебе пример: #include <iostream>
class A { int _x; public: virtual void f(int x) { _x = x; std::cout << "Class A: " << x << "\n"; } };
class B { int _x; public: virtual void f(int x) { _x = x; std::cout << "Class B: " << x << "\n"; } };
class AB : public A, public B { public: virtual void f(int x) { _x = x; std::cout << "Class C: " << x << "\n"; } }; Он не компилируется, потому что в AB::f не указано, какую переменную _x брать -- из подобъекта класса A или из подобъекта класса B. Если ты введёшь в класс AB переменную int _x, то методы A::f и B::f её НЕ УВИДЯТ! При вызове ab.A::f будет изменено поле ab.A::_x, при вызове ab.B::f будет изменено поле ab.B::_x, но поле ab._x меняться не будет. По этой причине доступ к состоянию потомка для методов-предков не будет. В языке Eiffel есть фича, названная renaming -- при наследовании можно указать, как назвать метод предка в потомке. Эта фича позволяет избегать конфликта имён полей и методов при множественном наследовании. В С++ такой фичи нет. Надо ручками вводить промежуточные классы, в которых переопределяются методы, и множественно наследовать от промежуточных классов. Пример см. http://cpptips.hyperformix.com/cpptips/rename_virt_mi
|
|
« Последнее редактирование: 02-12-2007 17:13 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #26 : 03-11-2004 10:15 » |
|
Алик, А доступ к членам AB?
да, если написать так class AB { friend class A; friend class B;
A * a; B * b; };
то у А есть доступ к членам АВ
|
|
« Последнее редактирование: 02-12-2007 17:14 от Алексей1153++ »
|
Записан
|
С уважением Lapulya
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #27 : 03-11-2004 10:36 » |
|
lapulya, Только не "class AB : public A, public B ", а "class AB : public AA, public BB" Ну, это извраты за неимением красивого решения... Алик, мне почему-то каэться, что у тебя проблемы с проектированием классов, чтобы предки использовали данные потомков . Да они и знать не должны что там у них есть какието производные классы! Изврат, имхо, и полиморфизм вывернутый наизнанку. В моих классах(-предках) виртуальные функции вызываются для того, чтобы вернуть результат. Конкретнее, один из классов возвращает различные комбинации чисел. И каджую комбинацию надо вернуть пользователю. Можно сделать немеренно большой массив этих комбинаций. А можно возвращать их по одной, что и делается с помощью вызова виртуального метода. Этот виртуальный метод пользует комбинации как ему надо, естественно, используя и другие члены дочернего класса. (надеюсь, никого в ступор не ввел ) npak В языке Eiffel есть фича, названная renaming -- при наследовании можно указать, как назвать метод предка в потомке. Эта фича позволяет избегать конфликта имён полей и методов при множественном наследовании. В С++ такой фичи нет. Надо ручками вводить промежуточные классы, в которых переопределяются методы, и множественно наследовать от промежуточных классов.
Вот-вот, к такому печальному выводу я и пришел...
|
|
|
Записан
|
|
|
|
Алик
Постоялец
Offline
|
|
« Ответ #28 : 03-11-2004 10:40 » |
|
Алик, А доступ к членам AB?
да, если написать так class AB { friend class A; friend class B;
A * a; B * b; };
то у А есть доступ к членам АВ Да, но чтобы метод класса А получил доступ к членам класса AB, ему нужно передать ссылку на этот экземпляр AB, что не есть красиво, а есть то же изврат
|
|
« Последнее редактирование: 02-12-2007 17:15 от Алексей1153++ »
|
Записан
|
|
|
|
lapulya
Молодой специалист
Offline
|
|
« Ответ #29 : 03-11-2004 10:48 » |
|
Алик, Да, я уже поправил (и дал полный оригинал того, что было у меня прикинуто на эту тему) И все же это решение далеко от идеала... так что советую как прислушаться к замечанию зайца Алик, мне почему-то каэться, что у тебя проблемы с проектированием классов
рекомендую перепроектировать этот кусок (так сказать сделать локальный рефакторинг)
|
|
|
Записан
|
С уважением Lapulya
|
|
|
|