3 / 26 / 9
Регистрация: 29.08.2010
Сообщений: 204
1

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

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

Author24 — интернет-сервис помощи студентам
решил поучить паттерны, застрял малость на одном, а точнее на его реализации, паттер называеться Вариант, смысл его, убрать типизацию...
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;
 
 }
простенка программка, в которой создается список, и хочу засунуть в него елементы разных типов, и потом их вытянуть обратно, но у меня не получается(, подскажите как это сделать
понятно что мы создаем функцию которая возвращает обьект, но мы ж незнаем тип обьект...
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
14.02.2012, 23:56
Ответы с готовыми решениями:

Ввод текста, число строк которого заранее неизвестно
Здравствуйте. Понимаю, что это может быть избитой темой, но сам никак найти не могу. Проблема...

Ввести массив целых чисел, количество элементов которого заранее неизвестно
Ввести массив целых чисел, количество элементов которого заранее неизвестно. Признаком конца ввода...

Как обрезать строку? значение переменной MyStr заранее неизвестно.
Допустим есть такая переменная: MyStr='Это такая строка '; Как можно...

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

33
4768 / 2578 / 892
Регистрация: 29.11.2010
Сообщений: 5,575
15.02.2012, 09:05 2
Недостаток паттерна variant в том, что никак не проверить, что же он, собственно, содержит, а в самом С++ нет механизмов рефлексии.
Поэтому либо перебором, либо храните в нем только такие данные, тип которых по-настоящему не имеет значения.
1
Заблокирован
15.02.2012, 11:28 3
тут какая то непонятка с копирующим конструктором
: error C2558: class 'variant': нет доступных конструкторов копии или конструктор копии объявлен как 'explicit'
0
3 / 26 / 9
Регистрация: 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 тоесть мы заранее знаем что там находиться... толк от этого?
0
Заблокирован
15.02.2012, 14:35 5
Цитата Сообщение от HardMorg Посмотреть сообщение
тоесть мы заранее знаем что там находиться...
Я сколько ни пытался, мне так и не удалось идентифицировать тип объекта, по самому объекту.
За исключением костыльной техники typeof (она требует, что бы тип объекта предварительно прошёл регистрацию, времени компиляции. И не умеет идентифицировать фактический тип полиморфного объекта).

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

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

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


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

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

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

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

Не по теме:

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

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

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

Не по теме:


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

не понял Вас

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

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

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

C++
1
2
3
4
5
IBase* ptr = new Concrete(); //указатель на базовый класс 
                                        //нацелился на объект потомка.
 
ptr -> VirtualMethod(); //пожалста. Запускай любые 
                                //виртуальные методы потомка
0
3 / 26 / 9
Регистрация: 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();
}
вот это код не скомпилится
0
Заблокирован
15.02.2012, 22:15 13
А где в представленном коде имеет место быть переопределению виртуальных методов в потомке?
Ты вообще в курсе, как работает виртуальный полиморфизм на языке с++?
0
3 / 26 / 9
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 22:55  [ТС] 14
Цитата Сообщение от Bers Посмотреть сообщение
А где в представленном коде имеет место быть переопределению виртуальных методов в потомке?
Ты вообще в курсе, как работает виртуальный полиморфизм на языке с++?
В том же и прикол когда я спрашивал сначала Вы меня походу не так поняли или может я не так вопрос задал. На сколько я понимаю когда в классе есть хоты бы одна виртуальная функция то компилятор в классе ставит "невидимый" указатель на таблицу виртуальных методов.( функция - адрес)
Виртуальные методы нужны если нужно изменить поведение функции в классе потомке. Для каждого класса только 1 таблица. когда мы создаем объект класса наследника получается что вызывается конструктор базового класса в нем инициализуруется указатель на таблицу, а потом уже конструктор наследника в котором замещается адрес виртуальных методов. Если я неправ поправьте меня
0
Заблокирован
15.02.2012, 23:04 15
Цитата Сообщение от HardMorg Посмотреть сообщение
В том же и прикол когда я спрашивал сначала Вы меня походу не так поняли или может я не так вопрос задал. На сколько я понимаю когда в классе есть хоты бы одна виртуальная функция то компилятор в классе ставит "невидимый" указатель на таблицу виртуальных методов.( функция - адрес)
Виртуальные методы нужны если нужно изменить поведение функции в классе потомке. Для каждого класса только 1 таблица. когда мы создаем объект класса наследника получается что вызывается конструктор базового класса в нем инициализуруется указатель на таблицу, а потом уже конструктор наследника в котором замещается адрес виртуальных методов. Если я неправ поправьте меня
На самом деле "невидимый" указатель на таблицу виртуальных функций присутствует не в "классе", а в "объектах" этого класса. И честно говоря, я не в полне себе понимаю, почему так было сделано.
Ведь этот указатель у всех объектов одного класса один и тот же. По мне так, тут статик мембер просится.

Ну да не суть.

Вот здесь можно узнать про "низкоуровневую" кухню. Доступно описано: http://www.devdoc.ru/index.php... l_base.htm
0
3 / 26 / 9
Регистрация: 29.08.2010
Сообщений: 204
15.02.2012, 23:09  [ТС] 16
Оо, за ссылку спасибо щас почитаю) но на мой вопрос так никто и не ответил(
0
Эксперт С++
5055 / 3115 / 271
Регистрация: 11.11.2009
Сообщений: 7,044
15.02.2012, 23:13 17
HardMorg, а какой вопрос-то? Почему код не компилируется? Да потому, что у вас базовый класс содержит таблицу виртуальных функций всего лишь с одной записью, а производный - с двумя. Базовый класс ничего не знает о том, что было добавлено в производном, соответственно, к этим изменениям мы не можем достучаться и через указатель на базовый класс.
0
Заблокирован
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
}
0
DU
1500 / 1146 / 165
Регистрация: 05.12.2011
Сообщений: 2,279
15.02.2012, 23:19 19
Ведь этот указатель у всех объектов одного класса один и тот же. По мне так, тут статик мембер просится.
Как вы себе это представляете такую (на статик мембере) реализацию полифорфного поведения?
0
4768 / 2578 / 892
Регистрация: 29.11.2010
Сообщений: 5,575
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;
}
0
15.02.2012, 23:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.02.2012, 23:19
Помогаю со студенческими работами здесь

Как выгрузить из ресурсов текстовый файл, если имя его заранее неизвестно ?
Всем привет! Собственно, в ресурсах есть несколько текстовых файлов. В программе я получаю имя...

Как определить тип переменной, ссылающейся на определённый класс? Нужен именно тип, а не ссылка на обьект!
interface HowDefineMyType { void info(); } class A implements HowDefineMyType { ...

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

Как возможно вернуть из функции обьект?
Подскажите как возможно вернуть из функции обьект Function l()as Document Dim ss as Document ss...


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru