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

Не могу отловить крайние случаи - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 16, средняя оценка - 4.94
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
30.09.2015, 19:36     Не могу отловить крайние случаи #1
Всем привет. Зарегистрировался на одном из многочисленных онлайн курсов по С++. Не могу "сдать" проверяющему сервису две задачи уже достаточно долго.
Условие первой:
Кликните здесь для просмотра всего текста
Напишите функцию, которая принимает на вход целочисленную матрицу M (другими словами, просто двумерный целочисленный массив) размера rows×cols, и возвращает транспонированную матрицу MT (тоже двумерный целочисленный массив) размера cols×rows. Если в M на пересечении i-ой строки и j-ого столбца стояло число x, то на пересечении j-ой строки и i-ого столбца в матрице MT тоже будет стоять число x, или другими словами MT[j][i]=M[i][j].

Обратите внимание, что вам неизвестно, каким именно способом выделялась память для массива M. Выделять память под массив MT можете любым удобным вам способом. Изменять исходную матрицу нельзя.

Требования к реализации: при выполнении этого задания вы можете определять любые вспомогательные функции. Вводить или выводить что-либо не нужно. Реализовывать функцию main не нужно.

Мой код:
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
#include <iostream>
#include <cstdlib>
 
using namespace std;
int **m = 0;
int **mt = 0;
int rows =3, cols = 5;
int main() {
    
    int ** transpose(const int * const * m, unsigned rows, unsigned cols);
    
    transpose(m, rows, cols);
    for (int i = 0; i != cols; ++i) {
        for (int j = 0; j != rows; ++j)
            cout << mt[i][j] << " ";
        cout << endl;
    }
    void free_array2d(int **m, int rows, int cols);
    return 0;
}
 
 
int ** transpose(const int * const * m, unsigned rows, unsigned cols){
    
    int ** create_array2d(int rows, int cols);
    m=create_array2d(rows, cols);
    mt = create_array2d(cols, rows);
    int count = 0;
    for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j)
            cout << m[i][j] << " ";
        cout << endl;
    }
    for (int i = 0; i != cols; ++i) {
        for (int j = 0; j != rows; ++j)
            mt[i][j] = m[j][i];
    }
    
    return mt;
}
 
 
int ** create_array2d(int rows, int cols) {
 
        int ** m = new int*[rows];
        m[0] = new int[rows*cols];
        for (size_t i = 1; i != rows; i++)
            m[i] = m[i - 1] + cols;
        int count = 0;
        for (int i = 0; i != rows; ++i) {
            for (int j = 0; j != cols; ++j){
                m[i][j] = count;
                count++;
            }
        }
 
    
    return m;
}
Условие второй:
Кликните здесь для просмотра всего текста
Напишите функцию поиска первого вхождения шаблона в текст. В качестве первого параметра функция принимает текст (C-style строка), в которой нужно искать шаблон. В качестве второго параметра строку-шаблон (C-style строка), которую нужно найти. Функция возвращает позицию первого вхождения строки-шаблона, если он присутствует в строке (помните, что в C++ принято считать с 0), и -1, если шаблона в тексте нет.

Учтите, что пустой шаблон (строка длины 0) можно найти в любом месте текста.

Требования к реализации: при выполнении данного задания вы можете определять любые вспомогательные функции, если они вам нужны. Вводить или выводить что-либо не нужно. Реализовывать функцию main не нужно.


Мое решение(возможно довольно кривое, т.к. давно пытаюсь сдать, кучу костылей натыкал):
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
#include <iostream>
using namespace std;
 
const char text[] = "";
const char pattern[] = "";
unsigned Strlen(const char *str);
int len_text = Strlen(text);
int len_pattern = Strlen(pattern);
int Strstr(const char *text, const char *pattern);
 
int main() {
    cout << Strstr(text, pattern);
    return 0;
}
 
int Strstr(const char *text, const char *pattern) {
    
    if (len_text < len_pattern) return -1;
    if ((len_text == 0) && (len_pattern == 0)) return 0;
    if ((len_text == 0) && (len_pattern != 0)) return -1;
    if ((len_text != 0) && (len_pattern == 0)) return 0;
    int j = 0;
    int i = 0;
    if ((len_text == 1) && (len_pattern == 1)) {
        if (*text == *pattern) { return 0; }
        else { return -1; }
    }
    else {
        for (i = 0; i < len_text; i++) {
            if (text[i] == pattern[j])
            {
                j++;
            }
            else
            {
                if (j > 0) i -= j;
                j = 0;  
            }
 
            if (j == len_pattern)
            {
                return i - len_pattern + 1;
            }
        }
    }
    if (i == len_text - len_pattern + 1) return -1;
 
    return -1;
}
 
unsigned Strlen(const char *str) {
    int count1 = 0;
    while (*str != 0) {
        str++;
        count1++;
 
    }
    return count1;
}
В идеале, подскажите как их исправить, ибо я уже задолбался с ними.
Но если просто укажите, на каких входных данных проги лажают, тоже хорошо будет.
P.S. само собой, функцию main на проверку не отправляю. При проверке обе программы компилируются, но на одном из тестов выдают неверный ответ.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
30.09.2015, 19:57     Не могу отловить крайние случаи #2
C++
1
2
int ** transpose(const int * const * m, unsigned rows, unsigned cols);
int ** create_array2d(int rows, int cols);
Это должно быть выше объявления main.
Зачем вы выделяете память для m внутри transpose? Память уже должна быть выделенной до вызова transpose.

create_array2d работает неверно.
C++
1
2
3
4
5
6
7
8
9
m = new int*[rows];
for(int i = 0; i < rows; ++i)
   m[i] = new int [cols];
 
 
/*Удаление*/
for(int i = 0; i < rows; ++i)
   detete[] m[i];
delete[] m;
Это не используемая переменная в transpose
C++
1
int count = 0;
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
30.09.2015, 20:13  [ТС]     Не могу отловить крайние случаи #3
Лишнюю переменную удалил, объявление вынес, но это никак не влияет.

Как и где выделить память заранее? В функции main нельзя (по условию, т.к. её не надо реализовывать), а до неё не получается - пишет "это объявление не содержит класс хранения или спецификатор типа".

По поводу create_array2d, что там не правильно? Само выделение? Оно преподносится в курсах как более эффективное, т.к. позволяет избежать фрагментации.
И сразу же вопрос по удалению выделенной памяти. Оно должно происходить в той же функции, что и выделят? До return? А что тогда вернёт return, если он память очистит? Не понимаю этого момента...
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
30.09.2015, 21:04     Не могу отловить крайние случаи #4
Сообщение было отмечено автором темы, экспертом или модератором как ответ
Цитата Сообщение от oPean Посмотреть сообщение
Оно должно происходить в той же функции, что и выделят?
Только если вам не нужно возвращать указатель на выделенную память. В вашем случае удалять нужно в main перед return 0.

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
#include <iostream>
#include <cstdlib>
 
using namespace std;
 
int ** create_array2d(const int& rows, const int& cols) 
{
   int **m = new int*[rows];
   for(int i = 0; i < rows; ++i)
      m[i] = new int [cols];
   return m;
}
 
int ** transpose(const int * const * m_, const int& rows, const int& cols)
{
    int **mt_ = create_array2d(cols, rows);
 
    for (int i = 0; i < cols; ++i) {
        for (int j = 0; j < rows; ++j)
            mt_[i][j] = m_[j][i];
    }
    
    return mt_;
}
 
/*Дублирующийся код выделяем в отдельные функции/процедуры*/
void show(const int * const * m_, const int& rows, const int& cols)
{
   for (int i = 0; i < rows; ++i) {
        for (int j = 0; j < cols; ++j)
            cout << m_[i][j] << " ";
        cout << endl;
    }
}
 
void destroy(int** m_, const int& rows)
{
   for (int i = 0; i < rows; ++i)
        delete[] m_[i];
   delete[] m_;
}
 
int main() 
{
    int rows =3, cols = 5;
    int **m = create_array2d(rows, cols);
    
    int count = 0;
    for (int i = 0; i < rows; ++i) // безопаснее использовать неравенства вместо != или ==
    {
         for (int j = 0; j < cols; ++j)
         {
              m[i][j] = count;
              count++;
         }
    }
    show(m, rows, cols);
 
    int **mt = transpose(m, rows, cols);
    show(mt, cols, rows);
    
    /*Обязательно чистим за собой!*/
    destroy(m, rows);
    destroy(mt, cols);
    return 0;
}
Оно преподносится в курсах как более эффективное
Может быть, просто я такого выделения пока не встречал

Добавлено через 6 минут
Цитата Сообщение от oPean Посмотреть сообщение
Обратите внимание, что вам неизвестно, каким именно способом выделялась память для массива M
Соответственно память должна быть выделена до transpose (что логично), т.е. в main.

Добавлено через 2 минуты
На будущее старайтесь не использовать глобальные переменные.

Добавлено через 20 минут
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
/*Если используете unsigned, то используйте его везде*/
unsigned Strlen(const char *str)
{
    unsigned count = 0;
    while (*str != 0) {
        ++str; // ++str быстрее str++
        ++count;
    }
    return count;
}
 
int Strstr(const char *text, const char *pattern)
{
    unsigned len_text = Strlen(text);
    unsigned len_pattern = Strlen(pattern);
    
    /*Ваши условия можно сократить до этих двух строк*/
    if (len_text < len_pattern) return -1;
    if (len_pattern == 0) return 0;
 
    unsigned textPos = 0;
    unsigned pattPos = 0;
    unsigned textPosOld;
    while (textPos < len_text)
    {
        textPosOld = textPos;
        while (text[textPos] == pattern[pattPos] && pattPos < len_pattern)
        {
            ++pattPos;
            ++textPos;
        }
        if (pattPos >= len_pattern)
            return textPosOld;
        else
        {
            pattPos = 0;
            textPos = textPosOld + 1;
        }
    }
    return -1;
}
 
int main()
{
    const char text[] = "abcdefghijk";
    const char pattern[] = "cde";
    cout << Strstr(text, pattern);
    return 0;
}
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
30.09.2015, 21:07  [ТС]     Не могу отловить крайние случаи #5
Я наверное не совсем понятно объяснил. Задание сдаётся в некий сервис, который сам проверяет. На этом сервисе, судя по всему, прописана функция main с вызовом transpose. Поэтому в условии написано
Вводить или выводить что-либо не нужно. Реализовывать функцию main не нужно.
В поле ввода решения вот такой вот "шаблон".
int ** transpose(const int * const * m, unsigned rows, unsigned cols){
...
}
Соответственно, самостоятельно ничего вызвать из функции main нельзя(к ней просто нет доступа), а так же нельзя объявить в ней переменные, поэтому приходится их делать глобальными. И память освободить из функции main тоже нельзя.
После небольших танцев с бубном, ваше решение прошло, за что большое спасибо. Сейчас осталось разобраться, чем оно в моём случае отличается (т.к. дело, понятно, не в освобождении памяти), скорее всего в том, что память нужно было выделить до вызова функции.
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
30.09.2015, 21:17     Не могу отловить крайние случаи #6
Цитата Сообщение от oPean Посмотреть сообщение
Я наверное не совсем понятно объяснил
Скорее вы просто не поняли задание

Цитата Сообщение от oPean Посмотреть сообщение
И память освободить из функции main тоже нельзя.
Можно и нужно внутри вашей тестовой программы.

Цитата Сообщение от oPean Посмотреть сообщение
Реализовывать функцию main не нужно.
Это значит лишь то, что в окно решения пихать main не надо. Но без нее вы не сможете предварительно проверить правильность своего решения.

Цитата Сообщение от oPean Посмотреть сообщение
прописана функция main с вызовом transpose
Так и есть. И у них память очищается в ней. Мы просто продублировали в своем main тот функционал, чтобы проверить правильность transpose. Процедура show также введена для нас и в решение она не пойдет.

Добавлено через 2 минуты
Цитата Сообщение от oPean Посмотреть сообщение
После небольших танцев с бубном, ваше решение прошло, за что большое спасибо
Бубен вообще любимый музыкальный инструмент программистов... Не за что)
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
30.09.2015, 21:58  [ТС]     Не могу отловить крайние случаи #7
Второе решение принялось, всё понятно (кроме, разве что, того, почему моя не проходила)). Ещё раз спасибо, я на неё кучу времени угрохал.

А функцию main у себя в VS я само собой писал. И память старался очищать(тут просто не получалось, поэтому я на время забил и занялся отловом крайних случаев, на которых прога проваливает тест).
А вот выделял память не в том месте, теперь буде знать.
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
30.09.2015, 22:02     Не могу отловить крайние случаи #8
Чтобы понять где ошибка можно например расписать алгоритм на бумаге в виде блок схемы, а еще очень помогает пошаговая отладка.
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
30.09.2015, 22:05  [ТС]     Не могу отловить крайние случаи #9
А вот в том то и дело, что на бумаге, да и при пошаговой отладке, всё выглядело ок. И я не смог подобрать никаких входных данных, чтобы прога не сработала (длины строки\подстроки 0,1, равные длины, большие длины, неполное вхождение, повторное вхождение, похожие вхождения...).
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
05.10.2015, 21:19  [ТС]     Не могу отловить крайние случаи #10
И снова у меня вопрос, снова по тому же курсу) Задание своеобразное... Если честно, вообще не въехал.
Условие:
Кликните здесь для просмотра всего текста
Определен следующий класс (он также приведен в комментарии в шаблоне кода):

C++
1
2
3
4
5
6
7
struct Cls {
    Cls(char c, double d, int i);
private:
    char c;
    double d;
    int i;
};
Как видно, все поля этого класса закрытые, ваша задача реализовать несколько функций, которые дают полный доступ к этим полям (см. шаблон кода), не смотря на то, что они закрытые.

Внимание: предполагаемое решение этого задания существенно опирается на Undefined Behaviour и является исключительно учебным, но полезно для лучшего понимания того, как работают модификаторы доступа. Решение было проверено на различных компиляторах (g++/clang++/icc/msvc), но мы настоятельно не рекомендуем использовать подобные трюки в боевом коде.

Требования к реализации: при решении этого задания вам разрешается заводить любые вспомогательные функции и классы, но не изменять определение класса Cls. Не нужно вводить или выводить что-либо, также не нужно определять функцию main.


И шаблон:
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
/*
 * Класс Cls определен точно таким образом:
 *
 * struct Cls {
 * Cls(char c, double d, int i);
 * private:
 *     char c;
 *     double d;
 *     int i;
 * };
 *
 */
 
// Эта функция должна предоставить доступ к полю c объекта cls.
// Обратите внимание, что возвращается ссылка на char, т. е.
// доступ предоставляется на чтение и запись.
char &get_c(Cls &cls) {
    /* ... */
}
 
// Эта функция должна предоставить доступ к полю d объекта cls.
// Обратите внимание, что возвращается ссылка на double, т. е.
// доступ предоставляется на чтение и запись.
double &get_d(Cls &cls) {
    /* ... */
}
 
// Эта функция должна предоставить доступ к полю i объекта cls.
// Обратите внимание, что возвращается ссылка на int, т. е.
// доступ предоставляется на чтение и запись.
int &get_i(Cls &cls) {
    /* ... */
}
Напишите, пожалуйста, эти функции в заданных условиях. А главное, объясните что, как и почему.
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
05.10.2015, 21:59     Не могу отловить крайние случаи #11
Курс юного хакера?)
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
struct Cls {
    Cls(char _c, double _d, int _i);
private:
    char c;
    double d;
    int i;
};
 
/*Объявляем "близнеца" нашего взламываемого класса с одним мааааленьким отличием*/
struct ClsPubl
{
    ClsPubl(char _c, double _d, int _i);
public:
    char c;
    double d;
    int i;
};
 
/*Это вам для проверки*/
int main ()
{
    struct Cls obj('f', 0.1, 2);
    //Так как в памяти объект близнец и его члены располагаются также,
    //как это было бы в экземпляре исходного класса,
    //можем проделать следующий трюк с преобразованием указателей:
    struct ClsPubl * p = static_cast<ClsPubl*>(static_cast<void*>((&obj)));
    cout << p->c << " " << p->d << " " << p->i;
    getch();
    return 0;
}
Добавлено через 6 минут
Для заметки еще можно сделать немного по грязному:
C++
1
#define private public
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
05.10.2015, 22:22  [ТС]     Не могу отловить крайние случаи #12
Это базовый курс об основах C++)

Что-то у меня ничего не вышло, а главное, понимание не пришло.
Давайте по порядку...Что я должен написать в функциях? Я правильно понимаю, что в функцию передаётся ссылка на объект cls структуры Cls, а вернуть она должна так же ссылку, но на элемент с объекта cls (т.е. вся функция представлена в этом коде)?
C++
1
2
3
char &get_c(Cls &cls) {
    return &cls.c;
}
Если да, то я не понимаю, почему грязный метод (а это действительно довольно забавно и не совсем честно)) не прошёл, возможно там стоит от него защита.

Так же у меня была мысль объявить схожий класс, но с открытыми членами, но я не знаю как их "подружить". И если честно, то трюк с преобразованием я тоже не понял( Кроме того, по условию задания, функцию main реализовывать не надо, т.е. при сдача кода у меня нет к ней доступа - не совсем понятно что и куда дописывать из того, что есть в функции main. Просто скопировать 26-ую строку и вставить после нового класса не прокатило.
AncientPenguin
98 / 45 / 18
Регистрация: 09.08.2015
Сообщений: 367
05.10.2015, 22:38     Не могу отловить крайние случаи #13
Цитата Сообщение от oPean Посмотреть сообщение
при решении этого задания вам разрешается заводить любые вспомогательные функции и классы, но не изменять определение класса Cls.
Вроде можно потанцевать с бубном вокруг ключевого слова friend, давно на С++ не кодил, не помню точно как там.
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
05.10.2015, 23:17  [ТС]     Не могу отловить крайние случаи #14
Цитата Сообщение от AncientPenguin Посмотреть сообщение
Вроде можно потанцевать с бубном вокруг ключевого слова friend, давно на С++ не кодил, не помню точно как там.
Френда ещё не было в теоретической части, предполагается, что он не нужен.
Там в комментариях кто-то предлагает посмотреть, где в памяти расположены эти переменные, и потом обращаться к ним с соответствующим сдвигом. Но как это делать тоже не понятно (мне).
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
06.10.2015, 11:28     Не могу отловить крайние случаи #15
Сообщение было отмечено автором темы, экспертом или модератором как ответ
oPean, по порядку так по порядку.
Цитата Сообщение от oPean Посмотреть сообщение
Я правильно понимаю, что в функцию передаётся ссылка на объект cls структуры Cls, а вернуть она должна так же ссылку, но на элемент с объекта cls
Да все верно (надеюсь вы уже понимаете что class и struct в C++ это одинаковые сущности, различие лишь как раз в дефолтных модификаторах доступа).

Цитата Сообщение от oPean Посмотреть сообщение
т.е. вся функция представлена в этом коде
Это было бы верно, если бы поля класса были public и без амперсанта в return. Надеюсь это тоже понятно.

Цитата Сообщение от oPean Посмотреть сообщение
Если да, то я не понимаю, почему грязный метод (а это действительно довольно забавно и не совсем честно)) не прошёл, возможно там стоит от него защита.
Если вы про #define то его использование просто не подразумевается заданием ибо подразумевается использование только вспомогательных методов и/или классов. Трюки с define вообще отличаются простотой и извращенностью. Обозначит какой-нибудь обиженный сотрудник где-нибудь в дебрях кода
C++
1
#define true false
или
C++
1
#define int64_t int32_t
, и устроит всем хардпати по отладке.

Я покажу на примере одной функции ибо ленив, а заодно вы сами потренируетесь на остальных и закрепите:
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
/*Подозреваемый. У него крепкая психика и нет очевидных слабостей, показания из него не выбить.*/
struct Cls {
    Cls(char _c, double _d, int _i);
private:
    char c;
    double d;
    int i;
};
 
/*Брат-близнец подозреваемого. Он знает все о грязных делишках Cls, но сдавать его не спешит, брат все же.*/
struct ClsPubl
{
   /*Суть в том, чтобы подельник был полной копией подозреваемого (только в этом случае поля и методы одного класса будут находится в памяти по тем же смещениям, что и у другого), за исключением наличия семьи и детей.*/
    ClsPubl(char _c, double _d, int _i);
public: /*<--- слабое место в психологии преступника - его близкие.*/
    char c;
    double d;
    int i;
};
 
/*Мы - детективы и уже битый час строим из себя "хорошего полицейского", но все бестолку.*/
/*Пришло время поиграть в "плохих полицейских" с братом подозреваемого...*/
 
char &get_c(Cls &cls) {
    void* voidptr = static_cast<void*>(&cls); /*Преобразуем указатель типа Сls* к типу void*. Как бы между делом замечаем поразительное внешнее сходство с непутевым братом.*/
    struct ClsPubl * p = static_cast<ClsPubl*>(voidptr); /*Преобразуем указатель типа void* к типу ClsPubl*, чтобы получить доступ к полям и методам. Далее говорим, что у нас таки есть свидетель, опознавший вашего брата (блеф, но иначе никак)! Но может это были вы? Что будет если вас посадят вместо него за его преступление? Как потом жить вашей семье? Ведь у них все отнимут в качестве компенсации!*/
    return p->c; /*Парень понимает, что у него нет выхода, и сдает брата-преступника. Преступник наказан, у детективов премия и бурный секс дома. Happy end!*/
    /* Прямое преобразование Сls* к ClsPubl* нелегально и компилятор не пропустит (приравнивается к избиению заключенных), поэтому вначале кастуем к void*. */
}
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
06.10.2015, 11:45  [ТС]     Не могу отловить крайние случаи #16
UltraPenguin, и снова вы меня спасаете, спасибо большое)

Надо вечером почитать про этот static_cast поподробнее... Такое приведение вообще часто используется в реальных условиях?
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
06.10.2015, 11:56     Не могу отловить крайние случаи #17
Цитата Сообщение от oPean Посмотреть сообщение
Такое приведение вообще часто используется в реальных условиях?
Если говорить о доступе к приватным членам, то в здравом уме никогда (о чем недвусмысленно написали авторы курса в задании). Если говорить о приведении типов объектов вообще то да, очень часто, причем практически во всех языках (даже не придумаю сходу где не используется) явно или неявно, так или иначе. В том числе кастование тесно связано с таким понятием в ООП как полиморфизм.
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
08.10.2015, 20:17  [ТС]     Не могу отловить крайние случаи #18
Я, наверное, ещё не раз достану с этим курсом=)
Задание:
Кликните здесь для просмотра всего текста
Ваш класс должен печатать (используя std::cout) текстовое представление арифметического выражения. Т.е. для объекта класса Number он должен напечатать число, которое в нем хранится, а для объекта класса BinaryOperation он должен напечатать левый операнд, затем операцию, а затем правый операнд.

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

Классы иерархии Expression и абстрактный класс Visitor приведены в комментарии в шаблоне для удобства.

При проверке задания лишние пробелы или лишние скобки будут игнорироваться, т.е. вывод "1+2" эквивалентен выводу "( ( 1 ) + ( 2 ) )", а вот вывод "1 + 2 * 3" не эквивалентен выводу "((1 + 2) * 3)". Вы можете попытаться минимизировать количество скобок в выводе, но это не требуется.

Требования к реализации: при выполнении задания вы можете заводить любые вспомогательные классы или функции, но не нужно реализовывать функцию main или менять реализацию классов иерархии Expression.


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
/*
struct Number;
struct BinaryOperation;
 
struct Visitor {
    virtual void visitNumber(Number const * number) = 0;
    virtual void visitBinaryOperation(BinaryOperation const * operation) = 0;
    virtual ~Visitor() { }
};
 
struct Expression
{
    virtual double evaluate() const = 0;
    virtual void visit(Visitor * vistitor) const = 0;
    virtual ~Expression();
};
 
struct Number : Expression
{
    Number(double value);
    double evaluate() const;
 
    double get_value() const { return value; }
 
    void visit(Visitor * visitor) const { visitor->visitNumber(this); }
 
private:
    double value;
};
 
struct BinaryOperation : Expression
{
    BinaryOperation(Expression const * left, char op, Expression const * right);
    ~BinaryOperation();
    double evaluate() const;
 
    Expression const * get_left() const { return left; }
    Expression const * get_right() const { return right; }
    char get_op() const { return op; }
 
    void visit(Visitor * visitor) const { visitor->visitBinaryOperation(this); }
 
private:
    Expression const * left;
    Expression const * right;
    char op;
};
*/
 
#include <iostream>
 
/* Этот класс вам нужно реализовать */
struct PrintVisitor : Visitor {
    void visitNumber(Number const * number)
    {
       std::cout << number->get_value() << " ";
    }
 
    void visitBinaryOperation(BinaryOperation const * bop)
    {
        bop->get_left()->visit(this);
        std::cout << '(' << bop->get_left() << bop->get_op() << bop->get_right() << ')' << " ";
        bop->get_right()->visit(this);
    }
};
То, что не закоменчено - моих рук дело, остальное "шаблон". Решение не принимается, но я не могу протестить, чтобы посмотреть что не так.
Пишу в main, например
C++
1
Number *n = new Number(32.0);
и VS2012 выдает ошибку линковщика "ссылка на неразрешенный внешний символ "public: __thiscall Number::Number(double)" (??0Number@@QAE@N@Z) в функции _main".
Я так почитал в интернете, походу дело даже не в коде, а что то с настройкой VS. Но не уверен. Подскажите, пожалуйста, в чем дело.
UltraPenguin
222 / 88 / 22
Регистрация: 20.03.2014
Сообщений: 296
Завершенные тесты: 1
09.10.2015, 11:19     Не могу отловить крайние случаи #19
А у вас точно реализован конструктор:
Цитата Сообщение от oPean Посмотреть сообщение
C++
1
Number::Number(double)
?

Если нет, то линковщик просто не знает как выполнять эту функцию и конструировать объект Number. Чтобы проверить нужно реализовать весь функционал, приведенный в шаблонах.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.10.2015, 18:24     Не могу отловить крайние случаи
Еще ссылки по теме:

Отловить деление на ноль C++
Составить программу вычисления корня. Учесть случаи, когда корень не может быть вычислен C++
Поменять местами крайние элементы стека C++

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

Или воспользуйтесь поиском по форуму:
oPean
0 / 0 / 0
Регистрация: 30.09.2015
Сообщений: 44
09.10.2015, 18:24  [ТС]     Не могу отловить крайние случаи #20
UltraPenguin, да, был такой косяк. Поправил - ничего не изменилось, та же ошибка при компиляции. А больше вроде нечего реализовывать...
Там в комментариях у одного была проблема, когда компилятор ругался как раз таки на конструктор Number, вот ему помогло.

Добавлено через 11 минут
А, не. Нашёл ошибку. Буду разбираться.
Yandex
Объявления
09.10.2015, 18:24     Не могу отловить крайние случаи
Ответ Создать тему
Опции темы

Текущее время: 16:55. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru