| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > C/C++: Общие вопросы > Указатель на класс |
| Автор: sergeeff 14.2.2003, 20:04 |
| Идея такова (навеяна долгой работой на С): class A { public: F1() {...} }; class B public: F1() {...} }; A *a; B *b; a = new A; b = new B; в теле программы надо реализовать некий указатель PTR, который работает примерно так if (...) PTR = a; else PRT = b; PTR->F1(); Ясно, что это необычный указатель, но большое желание такой подход реализовать Может знает кто про то как? С почтением |
| Автор: Nastya 14.2.2003, 20:55 |
| Не знаю на сколько я право, но.. 1. Такой подход точно сработает если один класс базовый, а другой дочерний. Указатель типа базового класса может хранить адресс дочерноего, но тогда функцию эжелательно сделать вертуальной. 2. А если заложить преобразование типов из одного класса в другой? Надо поробовать |
| Автор: Step 14.2.2003, 21:49 |
| ptr - указатель а потом ((CA*)ptr)=а; Соответственно ((CВ*)ptr)=b; Главное преобразование типов |
| Автор: Paradox 14.2.2003, 21:51 |
| А что если сделать void* a |
| Автор: Step 14.2.2003, 21:58 |
| именно воид с преобразование перед использованием |
| Автор: sergeeff 15.2.2003, 05:27 |
| Всем спасибо за отклики. Я сегодня почитав кое-какие умные книги (книга - источник знаний!) все реализовал. Ближе всех оказалась Nastya. Причем функцию не просто "желательно сделать виртуальной", а просто неопходимо сделать виртуальной в базовом классе. Замечания и советы про указатель типа void * тут никак не работают. Для всеобщего сведения - обычный pointer в Windows - 4 байта, а указатель на класс - длиннее. Так что это физически просто другой объект. Ну и вот вам живой пример реализации:#include <stdio.h> class C { public: virtual void F1(void) {}; }; class A : public C { public: void F1(void) { printf("Class A : F1()\n"); } }; class B : public C { public: void F1(void) { printf("Class B : F1()\n"); } }; int main(void) { A *a; B *b; C *c; a = new A; b = new B; c = a; c->F1(); c = b; c->F1(); return (0); } Всем спасибо за советы и с Валентиновым Днем! |
| Автор: dim 15.2.2003, 05:55 | ||
Ну это ты загнул |
| Автор: brb 15.2.2003, 07:07 | ||||
| А если классы не "родственники"? Нет ни базового ни дочернего, не сыновьего и не родительского как, впрочем, и было указано изначально! Пусть даже функция та же. По иф-элс можно, конечно, поинтер направить на разные классы, но вот вызывать
|
| Автор: sergeeff 15.2.2003, 23:21 | ||||
Это видно даже в отладчике. Указатель на класс отображается не просто как адрес, а как структура, но раскрыть он ее не может. Не помню в какой книге было написано, что этот указатель не то 6, не то 8 байт.
А если классы не "родственники", то перенаправить указатель тоже не удасться (компилятор не позволит, читай Строуструпа - можно привести поинтер только к базовому типу, то есть к родительскому классу). |
| Автор: brb 16.2.2003, 01:53 | ||
Вот за это я и люблю С. Я всяко умнее любого компилятора! На предупреждение - согласен, а иначе это уже советская власть и плюсплюсфикация всей страны! Жаль. |
| Автор: Nastya 17.2.2003, 21:03 |
| Указатель на класс 4 байта и указатель на воид прекрасно приводится к укозателю на класс. Проводим эксперемент class A{.....} void main() { A* a; cout<<sizeof(a); //4! a=(A*)malloc(sizeof(A)); a->...... delete a; } //Что и требовалось доказать |
| Автор: brb 18.2.2003, 00:49 | ||
| Nastya Вы доказали, что С и С++ "родственники"
Товарищ sergeeff не понимает? |
| Автор: SelfDestructor 18.2.2003, 01:34 |
| Для этой цели иногда приходится специально добавлять абстрактный базовый класс для классов A и B: class C { public: virtual void F1(void) = 0; }; А воидовые указатили это моветон =))) |
| Автор: dim 18.2.2003, 04:25 | ||
Что на это можно сказать - только одно: учи матчасть. А то так могут появится указатели и в 7 и 9 байт. |
| Автор: Fantasist 18.2.2003, 04:44 | ||||||||||
Вполне можно воспользоваться преобразованием типов. В стиле С:
В стиле С++:
Но оба варианта гораздо хуже виртуальных функций. Про преобразования типов и возникающие при этом опасности можно расказывать и обсуждать долго.
Это точно. В отладчике показывается структура на которую указывает указатель, а не структура самого указателя. |
| Автор: brb 18.2.2003, 05:50 | ||||
| Fantasist В стиле С все понятно и прозрачно до слез... Про ++
это в стандарте С++? Просто спрашиваю. Догадаться можно, но не очевидно, впочем, это относится исключительно ко мне! Про размер указателя. В Ветхом Завете (а я и есть ветхозаветник) Керниган и Ричи писано, что для определения размера есть sizeof(). В Новом(читай Страуструп) я не помню НИЧЕГО отрицающего Ветхий. Ни в том ни в другом я не помню ни слова про отладчики, а по сему все разговоры про размер указателя определенный отладчиком считаю ЕРЕСЬЮ!!! Для особо еретичных рекомендую вместо сожжения на костре выполнить:
Что же может быть красивее старого доброго С...однострочный комментарий // из ++ |
| Автор: Fantasist 19.2.2003, 02:28 | ||
Ага. У нас что, в FAQ ничего про это нету? Такие приведения в новом стиле были введены по нескольким причинам. Одна из них - удобочитаемость. То есть такое преобразование легко найти в тексте, и более понятно, что этим преобразованием ты хотел добиться. То есть: reinterpret_cast - преобразование чего угодно к чему угодно. Хорошим стилем считается, чтобы преобразований подобного рода было в коде поменьше. static_cast - преобразование по правилам приведения. То с помощью тех преобразований, которые определенны в языке, или оперделены пользователем. Но тут я гарантировать за правильность объяснения не поручусь dynamic_cast - преобразование для приведения указателей на пользовательские типы (классы, структуры), с использованием Run-Time Type Information (если оно поддерживается компилятором). Класс к указателю на который приводиться какой-то указатель должны содержать как минимум один виртуальный метод, так как предполагается, что RTTI храниться в таблице виртуальных методов. То есть для: dynamic_cast<A*>(b) class A* должен содержать виртуальный метод (b, cоответсвенно, тоже указатель). const_cast - используется исключительно для снятия атрибута const и volatile, и больше ни для чего другого. |
| Автор: brb 19.2.2003, 06:48 | ||
Китайский язык тоже был разработан, причем, во множестве вариантов, весьма далеких один от другого, с целью удобочитаемости. Как показала практика, удобочитаемым он оказался только для китайцев. К тому же, вышеупомянутый язык легко обнаруживается в любом тексте. К сожалению, опять же, только китайскочитающими специалистами. И, соершенно очевидно, чего хотели добиться создатели китайского языка - чтобы в дальнейшем, миллиардное население решало демаграфические проблемы посредством языкознания. Теперь серьезно. Раз сделали, значит так должно быть лучше, но к этому тоже нужно время чтобы привыкнуть. Вот тогда, действительно станет и проще и понятнее и удобочитаемей. Имея привычку к классическому С, нахожу его и удобным, и легко находимым, и понятным, и удобочитаемым. Т.е я, по-видимому, говорю на древне-китайском |
| Автор: Vyacheslav 19.2.2003, 19:02 | ||
К сожалению классический С не поддерживает парадигмы ООП, которые вызвали, например, появление такого оператора dynamic_cast. А необходимость поддержки написания безопасного и повторно используемого года привели к тому, что С++ по сравнению с С стал языком более строгим и типизированным языком. Поэтому сейчас будет ошибочным считать, что С++ -это всего лишь С с классами (как это было на заре появления С++) . Это совсем другой язык и дальнейшее развитие его продолжается. Тут недавно проскользнула информация, что Borland и Microsoft предоставили в комитет по стандартизации свои варианты по организации поддержки в С++ компонентной модели. |
| Автор: brb 19.2.2003, 23:41 | ||
А вот это уже довод! С безусловно имеет гораздо больше степеней свободы, впочем для того и было сделано и именно поэтому я так и не подружился с Паскалем. Vyacheslav, Вы меня убедили. |
| Автор: Vyacheslav 20.2.2003, 18:59 |
| А я в свое время вынужден перейти с Паскаля (того самого первоначального от Вирта) на С, когда понял, что у меня больше времени уходило на разработку приемов по обману компилятора, чем на саму задачу (автоматизация экспериментов: ДВК, RT-11SJ). Первое впечатление от С после Паскаля - это чувство полной свободы. |
| Автор: brb 20.2.2003, 23:39 |
| И не кажется ли Вам, что ++ эту свободу отбирает? А я перешел на С с Ассемблера. Теперь, я бы назвал С АСМ++ |
| Автор: sergeeff 21.2.2003, 08:12 | ||
Тип то привести можно, так вы мне что предлагаете по всей программе таскать каким то образом type_cast приведение в левой части? На фиг такое использование указателя на класс. Вся идея и состоит в том, чтобы где-то в начале определится (программно) указателем на какой класс является текущий указатель и далее безболезненно пользоваться вызовом типа C->F1(...). Насчет размера указателя на класс - под Wintel это действительно пока что 4 байта |
| Автор: brb 21.2.2003, 08:44 | ||
| Глубокоуважаемый, товарищ sergeeff! Во-первых, сообщаю Вам, что обсуждался не вопрос удобства (в Вашем конкретном случае виртуальная функция - лучшее решение, как и указали другие более грамотные товарищи Во-вторых, посредством макро это все можно красиво и понятно спрятать, дабы в дальнейшем
А указатель он и в Африке указатель, несмотря на что он указывает, его sizeof() от этого не меняется. |