Форум программистов, компьютерный форум CyberForum.ru

Наследование, dynamic_cast и использование последнего в связке с первым - C++

Восстановить пароль Регистрация
Другие темы раздела
C++ практика на экзамене http://www.cyberforum.ru/cpp-beginners/thread548961.html
вобщем я перездаю экзамен и мне дано задание:"написать консольное приложение , которое позволяет пользователю ввести с клавиатуры 10-ть дробных чисел и вывести на экран максимальное число из этого ряда чисел". Наработок нету т.к я вобще нишуя не шарю. Прошу спасайте)
C++ B-Дерево. Поиск. Вставка. Удаление. Доброго всем дня,есть задача: Написать программу реализующую следующие действия в B-Дереве: Поиск. Вставка. Удаление. Так же у меня есть готовая программа на Delphy, если вдруг кто сможет перевести. unit BTree; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, http://www.cyberforum.ru/cpp-beginners/thread548958.html
Перегрузка операторов для класса МАССИВ C++
Привет. Есть класс "вектор" ("массив"), нужно переопределить операторы =, +, - , *, +=, -=, *= с целым числом. =, +=, -=, *=, как функции члены +, - , * как дружественные функции Вопрос вот в чем. Не важно каким образом переопределяем, но как добраться до определенного эл-та? например a = 5; или
Как в C++ реализовать такое вычисление (1/2tg(0.7x))* ((ln(x+1.48))/2)) C++
Уважаемые знатоки, как в C++ реализовать такое вычисление (1/2tg(0.7x))* ((ln(x+1.48))/2)) при помощи использования библиотеки OpenMP, для подсчёта времени на вычисление этого выражения каждым потоком, если пользователь задаёт количество потоков.
C++ Работа перемещающего загрузчика http://www.cyberforum.ru/cpp-beginners/thread548943.html
Добрый день, необходимо разработать приложение, моделирующее работу перемещающего загрузчика. Программа считывает двоичный файл следующей структуры: N A1 A2 ... AM D0 D1 ... DK N - кол-во ячеек с адресами данных. A - ячейки с адресами данных. D - ячейки с данными. Необходимо изменить значение в области данных по адресам A1 A2 ... AM на величину S, вводимую с клавиатуры. Ячейки в файле 16...
C++ Как организовать переменную ошибки? Привет Что такое вроде понятно. Например переопределяем оператор для массива, если запрашиваем индекс больше чем размер массива-то выводим сообщение об ошибке и прекращаем работу данной функции(то есть ф-ии переопред. оператора). А как организовать непонимаю. Создать класс вектор, содержащий ссылку на int, размерность вектора и переменную ошибки. Класс имеет конструкторы по умолчанию,... подробнее

Показать сообщение отдельно
Gepar
 Аватар для Gepar
1173 / 529 / 20
Регистрация: 01.07.2009
Сообщений: 3,511
15.04.2012, 14:46     Наследование, dynamic_cast и использование последнего в связке с первым
Задание: написать отдалённую симуляцию интерфейса в виде консольного приложения, тоесть класс окно, в которое можно засовывать различные контролы (кнопки, едитбоксы и прочее). Всё это должно писаться через наследование, в общем-то всё работает, кроме одного пунктика: dynamic_cast на определённом этапе возвращает NULL, а без него всё работает хорошо. Беда в том что я могу писать только класс, а main будет какраз-таки с dynamic_cast'ом и его я изменить не могу так что должен под него подстраиваться.
Структура программы простая как доска, есть класс CControl от которого все контролы наследуются:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class CControl
{
public:
    //инициализация переменных с значениями координат элемента, их ID и заголовок (title)
    CControl(int _ID, double xPos1, double yPos1, double xPos2, double yPos2,  const string& _type, const string& _title="")
    :ID(_ID), type(_type), title(_title), x1(xPos1), y1(yPos1), x2(xPos2),y2(yPos2),printFromWindow(false),specialCBprint(false){}
 
 
    virtual void Print(ostream& os) const
    {
     //неважно
    }
 
    friend ostream& operator<<(ostream& os, const CControl& right)
    {
        right.Print(os);
        return os;
    }
 
    int ID;// our ID
    string type;// Button/Label/...
    string title;//"Ok" /"Cancel"/...
 
    //coordinats
    double x1;
    double y1;
    double x2;
    double y2;
};
Есть вот наследник с которым возникла проблема:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class CInput: public CControl
{
public:
     //инициализация координат, ID и заголовка класса родителя
    CInput(int ID, double xPos1, double yPos1, double xPos2, double yPos2, const string& title)
    :CControl(ID, xPos1, yPos1, xPos2, yPos2, "Input", title) {}
    
    //возможность поменять заголовок (title). Специфичный метод, есть только у этого класса
    void SetValue(const string& val)
    {
        title= val;
    }
};
Вот другой наследник для примера чтобы ясно было как все остальные выглядят. Он попроще и с ним проблем нет так как никаких специфичных методов у него нет.
C++
1
2
3
4
5
6
class CButton: public CControl
{
public:
    CButton(int ID, double xPos1, double yPos1, double xPos2, double yPos2, const string& title)
    :CControl(ID, xPos1, yPos1, xPos2, yPos2, "Button", title) {}
};
И есть класс окно (CWindow) который помнит список всего чего в него понапихивали. Выглядит вот так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
class CWindow
{
private:
    //coordinats
    int fx1;
    int fy1;
    int fx2;
    int fy2;
 
    string title;
 
    //так я храню список всех контролов чтобы потом их возвращать при поиске
    //либо распечатывать
    struct ListControl
    {
        ListControl()
        :control(NULL), next(NULL){}
 
        ListControl(const CControl& cont)
        :control(new CControl(cont)), next(NULL) {}
 
        CControl* control;
        ListControl* next;
    } * head, *tail;
 
 
public:
    //конструктор по умолчанию, ничего особенного, проблема не в нём
    CWindow(const string& _title, int xPos1, int yPos1, int xPos2, int yPos2)
    :fx1(xPos1), fy1(yPos1), fx2(xPos2), fy2(yPos2), title(_title), countCB(0), head(NULL), tail(NULL) {}
 
 
    CWindow& Add(const CControl& obj)
    {
        if(! head)
        {
            head= tail= new ListControl(obj);
            Recalculate(head->control);//пересчитывает координаты в CControl (x1,x2,y1,y2), больше ничего не делает
        }
        else
        {
            ListControl* toAdd= new ListControl(obj);
            Recalculate(toAdd->control);//пересчитывает координаты в CControl (x1,x2,y1,y2), больше ничего не делает
            tail->next= toAdd;
            tail= toAdd;
        }
        return *this;
    }
 
    //поиск работает корректно, элемент с указанным ID он находит
    CControl* Search(int id) const
    {
        ListControl* temp= head;
        while(temp && temp->control->ID != id)
         temp= temp->next;
 
        return (temp ?  temp->control: NULL);
    }
};
И теперь проблемный main:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    CWindow a ( "Sample window", 10, 10, 600, 480 );
    a . Add ( CInput ( 11, 0.4, 0.1, 0.5, 0.1, "chucknorris" ) );
    a . Add ( CButton ( 1, 0.1, 0.8, 0.3, 0.1, "Ok" ) );
    
    //напоминаю что поиск работает корректно и он возвращает указатель на CControl с ID=11
    //CControl с ID=11 какраз и есть CInput
    CInput * il = dynamic_cast<CInput *> ( b . Search ( 11 ) ); // dynamic_cast вернёт NULL!!!!!!!!!!!!
    il -> SetValue ( "chucknorris@fit.cvut.cz" ); // crash crash crash!!!!!
 
 
   //Если попробовать так
   CInput* il= static_cast<CInput*> (b . Search ( 11 )); //всё ок, без проверок оно нормально приводиться
    il -> SetValue ( "chucknorris@fit.cvut.cz" );//вызовется и отработает корректно
 
 
   //Если попробовать так
   CInput* il= b . Search ( 11 );//всё ок, но компилятор выдаёт warning: invalid conversion from `CControl*' to `CInput*'|
   il -> SetValue ( "chucknorris@fit.cvut.cz" );//вызовется и отработает корректно
Что мне делать Как обмануть dynamic_cast и почему он вообще не справляется с задачей приведения типа?
Решение методу Search начать возвращать CInput не предлагать, помимо CInput я могу искать и CButton например, заранее ведь неизвестно что под тем ID будет храниться.

Могу выложить полный код в виде прикреплённого файла, но он несколько побольше (360 строк), я здесь всё почти выбросил кроме проблемного метода.

Добавлено через 19 минут
Проблема решена добавлением метода для добавления чисто CInput
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
    CWindow& Add(const CInput& obj)
    {
        if(! head)
        {
            head= tail= new ListControl;
            head->control= new CInput(obj);
            Recalculate(head->control);
            head->next= NULL;
        }
 
        else
        {
            ListControl* toAdd= new ListControl;
            toAdd->control= new CInput(obj);
            toAdd->next= NULL;
            Recalculate(toAdd->control);
            tail->next= toAdd;
            tail= toAdd;
        }
        return *this;
    }
Иначе видать ещё на этапе добавления при вызове функции Add происходил срез данных (я правильно понял?) и все специфичные возможности CInput урезались после чего dynamic_cast не мог узнать этот контрол.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
 
Текущее время: 00:04. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru