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

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 12, средняя оценка - 4.67
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
#1

Как вернуть обьект тип которого заранее неизвестно - C++

14.02.2012, 23:56. Просмотров 1548. Ответов 33
Метки нет (Все метки)

решил поучить паттерны, застрял малость на одном, а точнее на его реализации, паттер называеться Вариант, смысл его, убрать типизацию...
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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
#include <iostream>
#include <memory>
 
class Variant {
 
private:
    
    class base {
 
    public:
 
        base() {
 
            std::cout <<"base constr" << std::endl;
        }
        virtual ~base(){
            std::cout <<"base destr" << std::endl;
        };
 
    };
 
    template<class T>
    class type:public base {
 
    private:
        T object;
    public:
        type(T const& ob) {
            object = ob;
            std::cout <<"type constr" << std::endl;
        }
 
        T Get() {
            return object;
        }
 
        ~type() {
 
            std::cout <<"type destr" << std::endl;
        }
    };
 
    std::auto_ptr<base> pObject;
 
public:
 
    Variant() {
        std::cout <<"Vari2 constr" << std::endl;
 
    }
    
    template<class T>
    Variant(T  ob) {
        std::cout <<"Vari constr" << std::endl;
        pObject = std::auto_ptr<type<T>>(new type<T>(ob));
    }
 
    template<class T>
    Variant& operator = (T const&t) {
 
        pObject = std::auto_ptr<type<T>>(new type<T>(t));
        return *this;
    }
 
    template<class T>
    operator T() {
 
        type<T> &t = dynamic_cast<type<T>&>(*pObject);
        return t.Get();
    }
 
    ~Variant() {
 
        std::cout <<"Vari dest" << std::endl;
        
    }
};
 
 
class out_of_range : public std::exception {
 
public:
    out_of_range() { }
};
 
template<class Node, class T>
class iterator {
    
private:
    Node *current;
    
public:
    iterator(Node *node):current(node) { }
    
    void operator++() {
 
        if(!current)
            throw new out_of_range();
 
        current = current->getNext();
    }
 
    bool operator == (iterator const &other) {
 
        return current == other.current;
    }
 
    bool operator !=(iterator const &other) {
        
        return current != other.current;
    }
 
    Node* operator->() {
 
        return current;
    }
};
 
 
template<class T>
class node {
 
private:
    T value;
    node *next;
    node *prev;
public:
    node(T value) {
        next = NULL;
        prev = NULL;
        this->value = value;
    }
    
    node* getNext() {
        return next;
    }
 
    node* getPrev() {
        return prev;
    }
 
    void setPrev(node *n) {
        prev = n;
    }
    void setNext(node *n) {
        next = n;
    }
    T getValue() {
        return value;
    }
};
        
template<class T> 
class list {
 
public:
    typedef iterator<node<T>, T> iterator;
 
private:
    node<T> *root;
 
public:
    list():root(NULL) { };
 
    void push_back(T &value) {
 
        if(root) {
 
            node<T> *temp = root;
            while(temp->getNext()) {
                temp = temp->getNext();
            }
            temp->setNext(new node<T>(value));
            temp->getNext()->setPrev(temp);
 
        }else {
            root = new node<T>(value);
        }
 
    }
    
    T pop_back() {
 
        if(!root) 
            throw new out_of_range();
 
        if(!root->getNext()) {
            T value = root->getValue();
            delete root;
            root = NULL;
            return value;
        } else {
 
            node<T> *del = root;
            while(del->getNext()) {
                del = del->getNext();
            }
 
            T value = del->getValue();
            del->getPrev()->setNext(NULL);
            delete del;
            return value;
        }
    }
 
    void push_front(T value) {
 
        if(!root) {
            root = new node<T>(value);
        } else {
 
            node<T> *newnode = new node<T>(value);
            newnode->setNext(root);
            root->setPrev(newnode);
            root = newnode;
        }
    }
 
    T pop_front() {
 
        if(!root) 
            throw new out_of_range();
 
        if(!root->getNext()) {
            T value = root->getValue();
            delete root;
            root = NULL;
            return value;
        }else {
 
            T value = root->getValue();
            node<T> *newroot = root->getNext();
            delete root;
            root = newroot;
            root->setPrev(NULL);
            return value;
        }
    }
 
        
    iterator begin() {
 
        return iterator(root);
    }
 
    iterator end() {
        return iterator(NULL);
    }
 
    ~list() {
 
        while(root) {
 
            node<T> *del = root;
            root = root->getNext();
            delete del;
        
        }
    }
 
};
 
 
 void main() {
 
     {
        list<Variant> any;
        Variant var(1);
        any.push_back(var);
     }
 
 
    //any.push_back('a');
    ///any.push_back(3.14);
    //any.push_back(std::string("vasa"));
 
 
    // for(list<Variant>::iterator it = any.begin(); any.end() != it; it++);
    //   std::cout << it->getValue() << std::endl;
 
 }
простенка программка, в которой создается список, и хочу засунуть в него елементы разных типов, и потом их вытянуть обратно, но у меня не получается(, подскажите как это сделать
понятно что мы создаем функцию которая возвращает обьект, но мы ж незнаем тип обьект...
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
14.02.2012, 23:56     Как вернуть обьект тип которого заранее неизвестно
Посмотрите здесь:
C++ Разработать класс, обьект которого реализует "пользовательский" тип данных
Даны действительные числа a1, ., an. (n>=2 и заранее неизвестно). Выяснить, имеются ли среди чисел a1, ., C++
C++ Сколько выделить памяти, если заранее неизвестно количество вложенных классов
C++ Как описать переменную в классе, тип которой заранее неизвестен?
C++ Как можно объявить класс, заранее не зная его тип template.
C++ Как описать шаблонную переменную в классе, тип которой заранее неизвестен ?
C++ Даны действительные числа a1, ., a2n (n>=2 и заранее неизвестно). Получить: (a1- a2n)(a3- a2n-2)(a5- a2n-4)
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
lemegeton
2923 / 1352 / 135
Регистрация: 29.11.2010
Сообщений: 2,725
15.02.2012, 09:05     Как вернуть обьект тип которого заранее неизвестно #2
Недостаток паттерна variant в том, что никак не проверить, что же он, собственно, содержит, а в самом С++ нет механизмов рефлексии.
Поэтому либо перебором, либо храните в нем только такие данные, тип которых по-настоящему не имеет значения.
Bers
Заблокирован
15.02.2012, 11:28     Как вернуть обьект тип которого заранее неизвестно #3
тут какая то непонятка с копирующим конструктором
: error C2558: class 'variant': нет доступных конструкторов копии или конструктор копии объявлен как 'explicit'
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 12:41  [ТС]     Как вернуть обьект тип которого заранее неизвестно #4
Цитата Сообщение от Bers Посмотреть сообщение
тут какая то непонятка с копирующим конструктором
: error C2558: class 'variant': нет доступных конструкторов копии или конструктор копии объявлен как 'explicit'
Странно но у меня все нормально компилиться(10 визуал)

Добавлено через 2 минуты
Цитата Сообщение от lemegeton Посмотреть сообщение
Недостаток паттерна variant в том, что никак не проверить, что же он, собственно, содержит, а в самом С++ нет механизмов рефлексии.
Поэтому либо перебором, либо храните в нем только такие данные, тип которых по-настоящему не имеет значения.
блин, так я не пойму смысла с этого паттерна, если мы только может вытянуть данные таким способом
(Variant v(4); int a = v тоесть мы заранее знаем что там находиться... толк от этого?
Bers
Заблокирован
15.02.2012, 14:35     Как вернуть обьект тип которого заранее неизвестно #5
Цитата Сообщение от HardMorg Посмотреть сообщение
тоесть мы заранее знаем что там находиться...
Я сколько ни пытался, мне так и не удалось идентифицировать тип объекта, по самому объекту.
За исключением костыльной техники typeof (она требует, что бы тип объекта предварительно прошёл регистрацию, времени компиляции. И не умеет идентифицировать фактический тип полиморфного объекта).

Сколько ни пытался, так и не удалось извлечь на свет божий фактический тип полиморфного объекта.

Более того, полагаю, что на языке статической типизации подобное совершить просто невозможно.
Может быть есть какое то.. полухакерское решение...

Нельзя по указателю на базовый тип толкнуть не_виртуальный метод потомка.
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 19:15  [ТС]     Как вернуть обьект тип которого заранее неизвестно #6
Цитата Сообщение от Bers Посмотреть сообщение
За исключением костыльной техники typeof (она требует, что бы тип объекта предварительно прошёл регистрацию, времени компиляции. И не умеет идентифицировать фактический тип полиморфного объекта).
Обьясните что вы тут хотели сказать я то я просто еще не очень понимаю.


в Яве я видел нетепизировыне контейнеры.... значить все же можно по идеи реализовать и тут.

Не по теме:
Вот я не пойму почему когда указателю базового класса присвоить адрес класса наследника то в таблице виртуальных методов только изменит адрес того метода который переопределяеться в потомке, а виртуальные методы обьявленые в потомке невидны
Bers
Заблокирован
15.02.2012, 19:27     Как вернуть обьект тип которого заранее неизвестно #7
Цитата Сообщение от HardMorg Посмотреть сообщение
Вот я не пойму почему когда указателю базового класса присвоить адрес класса наследника то в таблице виртуальных методов только изменит адрес того метода который переопределяеться в потомке, а виртуальные методы обьявленые в потомке невидны
1. Когда указателю на базовый класс присваивается адрес потомка, то этот указатель тупо начинает смотреть на область памяти, где живет объект-потомок.

Никаких изменений ни в каких таблицах виртуальных функций не происходит.

2. Виртуальные методы базового класса, переопределенные в потомке, видны. И их можно запустить.
retmas
15.02.2012, 19:36
  #8

Не по теме:

Цитата Сообщение от HardMorg Посмотреть сообщение
std::auto_ptr<base> pObject;
вот из-за таких вот перлов и похерили auto_ptr. хотя все к лучшему. я так думаю...(с)

silent_1991
Эксперт С++
4960 / 3036 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
15.02.2012, 20:21     Как вернуть обьект тип которого заранее неизвестно #9
Цитата Сообщение от HardMorg Посмотреть сообщение
в Яве я видел нетепизировыне контейнеры
Насколько мне известно, в джаве нетипизированные контейнеры на самом деле вполне себе типизированные и используют в качестве типа элементов тип Object. Идеология языка предполагает однокорневую иерархию и все классы прямо или косвенно являются потомками класса Object, поэтому любой объект можно положить по ссылке типа Object.
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 21:11  [ТС]     Как вернуть обьект тип которого заранее неизвестно #10
Цитата Сообщение от silent_1991 Посмотреть сообщение
Насколько мне известно, в джаве нетипизированные контейнеры на самом деле вполне себе типизированные и используют в качестве типа элементов тип Object. Идеология языка предполагает однокорневую иерархию и все классы прямо или косвенно являются потомками класса Object, поэтому любой объект можно положить по ссылке типа Object.
Кстати да, я забыл что все наследуются от object)

Добавлено через 37 секунд
Цитата Сообщение от retmas Посмотреть сообщение

Не по теме:


вот из-за таких вот перлов и похерили auto_ptr. хотя все к лучшему. я так думаю...(с)

не понял Вас

Добавлено через 6 минут
Цитата Сообщение от Bers Посмотреть сообщение
1. Когда указателю на базовый класс присваивается адрес потомка, то этот указатель тупо начинает смотреть на область памяти, где живет объект-потомок.

Никаких изменений ни в каких таблицах виртуальных функций не происходит.

2. Виртуальные методы базового класса, переопределенные в потомке, видны. И их можно запустить.
или вы себе противоречите или я не понимаю. Сами сказали что при присвоению указателю на базовый класс присваивается адрес потомка, то этот указатель смотрит на область памяти где живет обькет-потом, ну так если он туда указывает почем не видно виртуальных функций которые обявлены в классе-потомке?
Bers
Заблокирован
15.02.2012, 21:18     Как вернуть обьект тип которого заранее неизвестно #11
Цитата Сообщение от HardMorg Посмотреть сообщение
или вы себе противоречите или я не понимаю. Сами сказали что при присвоению указателю на базовый класс присваивается адрес потомка, то этот указатель смотрит на область памяти где живет обькет-потом, ну так если он туда указывает почем не видно виртуальных функций которые обявлены в классе-потомке?
1. Где ты нашел противоречия?
2. Фраза "методы видны, и их можно запустить" ты прочел как "методы не видны, и их нельзя запустить" да?

C++
1
2
3
4
5
IBase* ptr = new Concrete(); //указатель на базовый класс 
                                        //нацелился на объект потомка.
 
ptr -> VirtualMethod(); //пожалста. Запускай любые 
                                //виртуальные методы потомка
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 21:50  [ТС]     Как вернуть обьект тип которого заранее неизвестно #12
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class base {
 
public:
    virtual void f()  {
 
    }
};
 
class C:public base {
 
public:
    void f() {
 
    }
    virtual void f2() {
    }
};
 
void main() {
 
    base *c = new C;
    c->f2();
}
вот это код не скомпилится
Bers
Заблокирован
15.02.2012, 22:15     Как вернуть обьект тип которого заранее неизвестно #13
А где в представленном коде имеет место быть переопределению виртуальных методов в потомке?
Ты вообще в курсе, как работает виртуальный полиморфизм на языке с++?
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 22:55  [ТС]     Как вернуть обьект тип которого заранее неизвестно #14
Цитата Сообщение от Bers Посмотреть сообщение
А где в представленном коде имеет место быть переопределению виртуальных методов в потомке?
Ты вообще в курсе, как работает виртуальный полиморфизм на языке с++?
В том же и прикол когда я спрашивал сначала Вы меня походу не так поняли или может я не так вопрос задал. На сколько я понимаю когда в классе есть хоты бы одна виртуальная функция то компилятор в классе ставит "невидимый" указатель на таблицу виртуальных методов.( функция - адрес)
Виртуальные методы нужны если нужно изменить поведение функции в классе потомке. Для каждого класса только 1 таблица. когда мы создаем объект класса наследника получается что вызывается конструктор базового класса в нем инициализуруется указатель на таблицу, а потом уже конструктор наследника в котором замещается адрес виртуальных методов. Если я неправ поправьте меня
Bers
Заблокирован
15.02.2012, 23:04     Как вернуть обьект тип которого заранее неизвестно #15
Цитата Сообщение от HardMorg Посмотреть сообщение
В том же и прикол когда я спрашивал сначала Вы меня походу не так поняли или может я не так вопрос задал. На сколько я понимаю когда в классе есть хоты бы одна виртуальная функция то компилятор в классе ставит "невидимый" указатель на таблицу виртуальных методов.( функция - адрес)
Виртуальные методы нужны если нужно изменить поведение функции в классе потомке. Для каждого класса только 1 таблица. когда мы создаем объект класса наследника получается что вызывается конструктор базового класса в нем инициализуруется указатель на таблицу, а потом уже конструктор наследника в котором замещается адрес виртуальных методов. Если я неправ поправьте меня
На самом деле "невидимый" указатель на таблицу виртуальных функций присутствует не в "классе", а в "объектах" этого класса. И честно говоря, я не в полне себе понимаю, почему так было сделано.
Ведь этот указатель у всех объектов одного класса один и тот же. По мне так, тут статик мембер просится.

Ну да не суть.

Вот здесь можно узнать про "низкоуровневую" кухню. Доступно описано: http://www.devdoc.ru/index.php/conte...rtual_base.htm
HardMorg
3 / 26 / 3
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 23:09  [ТС]     Как вернуть обьект тип которого заранее неизвестно #16
Оо, за ссылку спасибо щас почитаю) но на мой вопрос так никто и не ответил(
silent_1991
Эксперт С++
4960 / 3036 / 149
Регистрация: 11.11.2009
Сообщений: 7,027
Завершенные тесты: 1
15.02.2012, 23:13     Как вернуть обьект тип которого заранее неизвестно #17
HardMorg, а какой вопрос-то? Почему код не компилируется? Да потому, что у вас базовый класс содержит таблицу виртуальных функций всего лишь с одной записью, а производный - с двумя. Базовый класс ничего не знает о том, что было добавлено в производном, соответственно, к этим изменениям мы не можем достучаться и через указатель на базовый класс.
Bers
Заблокирован
15.02.2012, 23:13     Как вернуть обьект тип которого заранее неизвестно #18
Цитата Сообщение от HardMorg Посмотреть сообщение
что вызывается конструктор базового класса в нем инициализуруется указатель на таблицу, а потом уже конструктор наследника в котором замещается адрес виртуальных методов. Если я неправ поправьте меня
IBase* ptr = new Concrete(); //По идее, тут запускается конструктор именно потомка, а не предка.
Однако, по правилу наследования, конструктор потомка запустит конструктор предка.
Причем, туловище конструктора предка будет запущено прежде, чем туловище конструктора потомка:


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct base 
{
    base() { con <<"конструктор base"<<eEndl;} 
    base(int a) { con <<"конструктор base: "<<a<<eEndl;} 
};
 
struct derived:base
{ 
    derived():base(333)   //конструктор потомка толкает вперед себя 
                                 //конструктор предка в аргументом
    { con <<"конструктор derived"<<eEndl;} 
};
 
int main()
{
    STD; 
    
    derived rr; //конструктор base: 333
                //конструктор derived
}
DU
1481 / 1057 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
15.02.2012, 23:19     Как вернуть обьект тип которого заранее неизвестно #19
Ведь этот указатель у всех объектов одного класса один и тот же. По мне так, тут статик мембер просится.
Как вы себе это представляете такую (на статик мембере) реализацию полифорфного поведения?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
15.02.2012, 23:19     Как вернуть обьект тип которого заранее неизвестно
Еще ссылки по теме:
C++ Как вы шаблонном классе определить контейнер, тип которого совпадает с именем параметра шаблона?
Консоль даже не запускается, и + "выражение должно иметь тип указателя на обьект" C++
Как вывести обьект с cout ? C++
Значение lim-1 неизвестно. Как программа узнаёт размер? или это формальный параметр C++
Дано целое число. Найти «маленький» тип, которого достаточно для сохранения числа. C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
lemegeton
2923 / 1352 / 135
Регистрация: 29.11.2010
Сообщений: 2,725
15.02.2012, 23:19     Как вернуть обьект тип которого заранее неизвестно #20
Цитата Сообщение от Bers Посмотреть сообщение
И честно говоря, я не в полне себе понимаю, почему так было сделано.
Ведь этот указатель у всех объектов одного класса один и тот же. По мне так, тут статик мембер просится.
Переменная может вдруг изменить свой тип (приведение не дремлет), а для консистенции надо, чтобы виртуальные функции правильно вызывались. Если бы в самой переменной не было бы виртуальной таблицы, приведением можно было бы вызывать функции любых классов.

Пример.
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
#include <iostream>
#include <ctime>
#include <cstdlib>
 
class Base {
 public:
  virtual void foo() { std::cout << "Base" << std::endl; }
};
 
class A : public Base {
 public:
  virtual void foo() { std::cout << "A" << std::endl; }
};
 
class B : public Base {
 public:
  virtual void foo() { std::cout << "B" << std::endl; }
};
 
int main() {
  srand(time(0));
  Base *a;
  if (rand() % 2) 
    a = new A();
  else
    a = new B();
  a->foo();
  // в следующих трех выражениях будет вызвана одна и та же функция
  ((A*)a)->foo();
  ((B*)a)->foo();
  ((Base*)a)->foo();
  delete a;
}
Yandex
Объявления
15.02.2012, 23:19     Как вернуть обьект тип которого заранее неизвестно
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru