Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
Progrmmer69
0 / 0 / 1
Регистрация: 01.12.2016
Сообщений: 19
1

Программирование на языке C++ Шаблоны функций

05.08.2017, 23:33. Просмотров 740. Ответов 4

Помогите пожалуйста

В первом уроке вы реализовали простой шаблон ValueHolder, в этом задании мы используем его чтобы написать класс Any (интересно, что не шаблонный), который позволяет хранить значения любого типа! Например, вы сможете создать массив объектов типа Any, и сохранять в них int-ы, double-ы или даже объекты Array. Подробности в шаблоне кода.

Hint: в нешаблонном классе Any могут быть шаблонные методы, например, шаблонный конструктор.

Для реализации вам может потребоваться оператор dynamic_cast.

С++ предоставляет и более простой способ узнать конкретный класс по указателю (или ссылке) на базовый класс. Для этого можно использовать оператор dynamic_cast. Например, если у вас есть указатель Expression *, и вы хотите узнать, указывает ли этот указатель на самом деле на объект Number, то сделать это можно так:
C++
1
2
3
4
5
6
Expression *expression = parse(code);
Number *number = dynamic_cast<Number *>(expression);
if (number)
    std::cout << "It's a number" << std::endl;
else
    std::cout << "It is not a number" << std::endl;
Если expression действительно указывает на объект Number (или на один из его наследников, но в нашем примере их нет), то оператор dynamic_cast<Number *> вернет правильный указатель. Если expression указывает не на класс Number, то будет возвращен нулевой указатель. Т. е. если в переменной number хранится нулевой указатель, значит expression не указывает на Number на самом деле.

Для правильной работы оператора dynamic_cast в нашем примере требуется, чтобы класс Expression был полиморфным, т. е. в нем должна быть как минимум одна виртуальная функция (например, деструктор). Стандарт определяет работу dynamic_cast и с не полиморфными типами, но в этом случае никаких проверок типа времени исполнения выполняться не будет - часто, это не то, что требуется.

Если передать оператору dynamic_cast нулевой указатель, то он просто вернет нулевой указатель нужного типа, поэтому проверять указатель перед передачей в dynamic_cast не нужно.

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
#include <iostream>
using namespace std;
/*
* В первом уроке вы реализовали простой шаблон ValueHolder,
* в этом задании мы используем его чтобы написать класс Any (интересно, что не шаблонный),
* который позволяет хранить значения любого типа!
* Например, вы сможете  создать массив объектов типа Any,
* и сохранять в них int-ы, double-ы или даже объекты Array.
* Подробности в шаблоне кода.
* Hint: в нешаблонном классе Any могут быть шаблонные методы, например, шаблонный конструктор.
* */
 
struct ICloneable
{
    virtual ICloneable* clone() const = 0;
    virtual ~ICloneable() { }
};
 
// Поле data_ типа T в классе ValueHolder
// открыто, к нему можно обращаться
template <typename T>
struct ValueHolder : ICloneable {
 
    ValueHolder(T value) : data_(value) {};
 
    ValueHolder * clone() const {
        return new ValueHolder(*this);
    }
 
    ~ValueHolder() {}
 
    T data_;
};
 
 
// Это класс, который вам нужно реализовать
 
class Any
{
    // В классе Any должен быть конструктор,
    // который можно вызвать без параметров,
    // чтобы работал следующий код:
    //    Any empty; // empty ничего не хранит
public:
    Any() : data_(0){}
 
    // В классе Any должен быть шаблонный
    // конструктор от одного параметра, чтобы
    // можно было создавать объекты типа Any,
    // например, следующим образом:
    //    Any i(10); // i хранит значение 10
 
    template < class T >
    Any(T data) : data_(new ValueHolder<T>(data)){}
 
    // Не забудьте про деструктор. Все выделенные
    // ресурсы нужно освободить.
 
    ~Any(){
        delete data_;
    }
 
    // В классе Any также должен быть конструктор
    // копирования (вам поможет метод clone
    // интерфейса ICloneable)
 
    Any (Any const & obj) : data_(obj.data_->clone()) {}
 
    // В классе должен быть оператор присваивания и/или
    // шаблонный оператор присваивания, чтобы работал
    // следующий код:
    //    Any copy(i); // copy хранит 10, как и i
    //    empty = copy; // empty хранит 10, как и copy
    //    empty = 0; // а теперь empty хранит 0
 
    template <typename T>
    Any& operator=(const T & obj){
//        if (this != &obj) {
            delete data_;
            data_ = new ValueHolder<T>(obj);
//        }
        return *this;
    }
 
    Any& operator=(const Any & obj){
        if (this != &obj){
            delete data_;
            data_ = obj.data_->clone();
        }
        return *this;
    }
 
    // Ну и наконец, мы хотим уметь получать хранимое
    // значение, для этого определите в классе Any
    // шаблонный метод cast, который возвращает
    // указатель на хранимое значение, или нулевой
    // указатель в случае несоответствия типов или
    // если объект Any ничего не хранит:
    //    int *iptr = i.cast<int>(); // *iptr == 10
    //    char *cptr = i.cast<char>(); // cptr == 0,
    //        // потому что i хранит int, а не char
    //    Any empty2;
    //    int *p = empty2.cast<int>(); // p == 0
    // При реализации используйте dynamic_cast,
    // который мы уже обсуждали ранее.
    template <typename T>
    T* cast() {
        if (data_) {
            ValueHolder<T> *res = dynamic_cast<ValueHolder<T> *>(data_);
            if (res) {
                return &(res->data_);
            }
        }
        return 0;
    }
 
    ICloneable * data_;
};
Ошибка:
Compilation error
main.cpp:66:8: error: redefinition of 'struct ICloneable'
struct ICloneable
^
main.cpp:39:8: error: previous definition of 'struct ICloneable'
struct ICloneable
^
main.cpp:75:8: error: redefinition of 'struct ValueHolder<T>'
struct ValueHolder : ICloneable {
^
main.cpp:46:8: error: previous definition of 'struct ValueHolder<T>'
struct ValueHolder : ICloneable
^
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
05.08.2017, 23:33
Ответы с готовыми решениями:

Stepik.org Программирование на языке C++ Шаблоны функций
Помогите пожалуйста, уже который день не могу сделать программу. Шаблонный класс Array может...

Шаблоны функций 9 Step stepik.org Программирование на языке C++
Помогите пожалуйста, уже который день не могу сделать программу. Шаблонный класс Array может...

Шаблоны классов в языке с++.Нужна доступная информация.
Нужна информация о шаблонах классов в языке с++,что с чем едят,в доступной форме для...

Шаблоны функций: найти произведение всех отрицательных элементов и сумму всех положительных элементов до максимального
помогите с задачей условие таково. Дан одна мерный массив состоящий из целых чисел нужно найти...

шаблоны функций
Помогите пожалуйста с задачей: Разработайте программу, в которой реализовано нахождение количества...

4
zss
Модератор
Эксперт С++
8299 / 7369 / 4576
Регистрация: 18.12.2011
Сообщений: 19,502
Завершенные тесты: 1
06.08.2017, 08:25 2
В этом коде компилятор ошибок не видит.
Где main() ?
0
Progrmmer69
0 / 0 / 1
Регистрация: 01.12.2016
Сообщений: 19
06.08.2017, 11:15  [ТС] 3
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
int main() {
    Any empty;
    Any i(10);
    cout << "[1] i      = " << i.cast<int>() << endl;
    Any copy(i);
    cout << "[2] copy   = " << copy.cast<int>() << endl;
    empty = copy;
    cout << "[3] empty  = " << empty.cast<int>() << endl;
    cout << "[3] *empty = " << *empty.cast<int>() << endl;
    empty = 0;
    cout << "[4] empty  = " << empty.cast<int>() << endl;
    cout << "[4] *empty = " << *empty.cast<int>() << endl;
    int *iptr = i.cast<int>();
    cout << "[5] iptr   = " << iptr << endl;
    char *cptr = i.cast<char>(); // cptr = 0
    // cout << "[6] cptr=" << cptr << endl; // undefined behavior for char * == 0
    cout << "[6] cptr   = " << (void*)cptr << endl;
    Any empty2;
    int *p = empty2.cast<int>();
    cout << "[7] p      = " << p << endl;
    Any a = 20;
    cout << "[8] a      = " << a.cast<int>() << endl;
    a=0;
    cout << "[9] a      = " << a.cast<int>() << endl;
    a = 'w';
    cout << "[10] a     = " << a.cast<char>() << endl; // overloaded operator << for char *
    cout << "[10] a     = " << (void *)a.cast<char>() << endl;
    return 0;
 
    return 0;
}
просто на stepik мейн не нужен
0
GbaLog-
Любитель чаепитий
3181 / 1484 / 469
Регистрация: 24.08.2014
Сообщений: 5,225
Записей в блоге: 1
Завершенные тесты: 2
06.08.2017, 11:30 4
на gcc всё работает.
http://rextester.com/PGWHN54983
0
Progrmmer69
0 / 0 / 1
Регистрация: 01.12.2016
Сообщений: 19
06.08.2017, 13:29  [ТС] 5
да, но на stepik говорит что ошибка и код нужно улучшить
https://stepik.org/lesson/564/step/11?unit=887
кто-то додумался, и я все не могу понять как они это сделали.
Степ 11, если что.

Добавлено через 45 минут
все, я разобрался, вот такой код подходит:
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
// Эти классы реализовывать заново не нужно
struct ICloneable;
 
// Поле data_ типа T в классе ValueHolder
// открыто, к нему можно обращаться
template <typename T>
struct ValueHolder;
 
class Any{
public:
    // В классе Any должен быть конструктор,
    // который можно вызвать без параметров,
    // чтобы работал следующий код:
    //    Any empty; // empty ничего не хранит
    Any():ptr(0) {} 
 
    // Не забудьте про деструктор. Все выделенные
    // ресурсы нужно освободить.
    ~Any() {
        delete ptr;     
    }
 
    // В классе Any также должен быть конструктор
    // копирования (вам поможет метод clone
    // интерфейса ICloneable)
    Any(const Any & other):ptr(other.ptr ? other.ptr->clone() : 0) {}
    
    // В классе Any должен быть шаблонный
    // конструктор от одного параметра, чтобы
    // можно было создавать объекты типа Any,
    // например, следующим образом:
    //    Any i(10); // i хранит значение 10
    template<typename T>Any(const T val):ptr(new ValueHolder<T>(val)) {}
    
 
    // В классе должен быть оператор присваивания и/или
    // шаблонный оператор присваивания, чтобы работал
    // следующий код:
    //    Any copy(i); // copy хранит 10, как и i
    //    empty = copy; // empty хранит 10, как и copy
    //    empty = 0; // а теперь empty хранит 0
    Any & operator=(const Any & other) {
        if(this != &other) {
            delete ptr;
            ptr = other.ptr ? other.ptr->clone() : 0;
        }
 
        return *this;
    }
    template<typename T>Any & operator=(const T & val) {
        delete ptr;
        ptr = new ValueHolder<T>(val);
        
        return *this;
    }
    
 
    // Ну и наконец, мы хотим уметь получать хранимое
    // значение, для этого определите в классе Any
    // шаблонный метод cast, который возвращает
    // указатель на хранимое значение, или нулевой
    // указатель в случае несоответствия типов или
    // если объект Any ничего не хранит:
    //    int *iptr = i.cast<int>(); // *iptr == 10
    //    char *cptr = i.cast<char>(); // cptr == 0,
    //        // потому что i хранит int, а не char
    //    Any empty2;
    //    int *p = empty2.cast<int>(); // p == 0
    // При реализации используйте dynamic_cast,
    // который мы уже обсуждали ранее.
    template<typename T>T * cast() {
        if(ptr == 0)
            return 0;
        else {
            ValueHolder<T>* pvh = dynamic_cast<ValueHolder<T>*>(ptr);
            if(pvh == 0)
                return 0;
            else
                return &(pvh->data_);
        }
    }
    
    
private:
    ICloneable * ptr;
};
0
06.08.2017, 13:29
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
06.08.2017, 13:29

Шаблоны функций
Всем доброго времени суток. Встала такая проблема: //.h template &lt;class T&gt; T randf( T min, T max...

Шаблоны функций
Реализовать на языке С++ программу, в которой оформ-лены в виде шаблонов функций (массив передавать...

Шаблоны функций: умножить все нечётные по абсолютной величине элементы массива на среднее арифметическое его элементов
1. Реализовать на языке С++ программу, в которой оформ-лены в виде шаблонов функций (массив...


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

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

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