Форум программистов, компьютерный форум, киберфорум
Наши страницы

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

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.78
Ilot
Модератор
Эксперт С++
1823 / 1181 / 232
Регистрация: 16.05.2013
Сообщений: 3,118
Записей в блоге: 5
Завершенные тесты: 1
#1

Как создать свой поток и связать его с консолью - C++

07.03.2014, 10:41. Просмотров 1494. Ответов 13
Метки нет (Все метки)

Собственно возник такой вопрос: читаю Саттера пробую создать свой класс символов не чувствительный к регистру. Автор пишет, что для вывода на консоль требуется использовать поток со своим типом сравнения символов.
В классе basic_string определен оператор:
C++
1
2
3
4
  template<typename _CharT, typename _Traits, typename _Alloc>
    basic_ostream<_CharT, _Traits>&
    operator<<(basic_ostream<_CharT, _Traits>& __os,
           const basic_string<_CharT, _Traits, _Alloc>& __str);
Вопрос как создать объект типа basic_ostream<char, MyChar> (MyChar - мой тип сравнения символов) и связать его с консолью?
Для потока нашел только один открытый конструктор
C++
1
2
3
      explicit 
      basic_ostream(__streambuf_type* __sb)
      { this->init(__sb); }
Как его использовать?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
07.03.2014, 10:41
Здравствуйте! Я подобрал для вас темы с ответами на вопрос Как создать свой поток и связать его с консолью (C++):

Создать свой поток данных - C++
Не могу понять, возможно ли как то создать свой поток данных? Знаю есть файловые потоки, cin cout cerr, а как быть если мне нужен поток...

Как создать свой класс и подключить его в main? - C++
я новичок,хотел поинтересоваться,когда люди пишут программу,они сначала главную функцию main пишут,а потом пишут классы и подключают к main...

В окне перемещаются объекты, отталкиваясь от стенок окна. Каждый объект имеет свой поток, перемещающий его. Встретившись, объекты начинают двигаться - C++
В окне перемещаются объекты, отталкиваясь от стенок окна. Каждый объект имеет свой поток, перемещающий его. Встретившись, объекты...

Нужно создать базу данных (создать пустой бинарный файл). Через поток. Поток бинарного файла описать в виде локальной переменной внутри функции. - C++
Совсем не понял эту тему. Нужно создать базу данных (создать пустой бинарный файл). Через поток. Поток бинарного файла описать в виде...

Как улучшить свой код и его структуру? - C++
Изучил основы С++, сейчас активно изучаю SFML, Qt и глядя на код других людей я замечаю что мой код заведомо отличается, (хотя по сути то...

Как создать поток в Linux? - C++
Программеры! Подскажите, пожалуйста, как создавать потоки в Linux. В Windows есть CreateThread(), а в Linux как? Можно спросить иначе:...

13
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
07.03.2014, 11:45 #2
а зачем его создавать?
0
Ilot
Модератор
Эксперт С++
1823 / 1181 / 232
Регистрация: 16.05.2013
Сообщений: 3,118
Записей в блоге: 5
Завершенные тесты: 1
07.03.2014, 11:48  [ТС] #3
Цитата Сообщение от aLarman Посмотреть сообщение
а зачем его создавать?
Потому, что в стандартный поток вывести свою строку я не могу.
0
aLarman
643 / 564 / 89
Регистрация: 13.12.2012
Сообщений: 2,109
Завершенные тесты: 1
07.03.2014, 12:04 #4
я может быть чего то не понял но попробую предложить, если нужен класс не чувствительных к регистру символов, то их нужно приводить к одному их регистров (нижний или верхний)
вот набросал
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
class CharNorReqister
{
public:
    CharNorReqister(char InX)
    {
        x = tolower(InX);
    }
    CharNorReqister():x(0)
    {
 
    }
    friend istream & operator>>(istream & is, CharNorReqister & X)
    {
        char a;
        is >> a;
        X.x = tolower(a);
        return is;
    }
    friend ostream & operator<<(ostream & os, CharNorReqister & X)
    {
        os << X.x;
        return os;
    }
private:
    char x;
};
дальше доопределить методы сравнений и операторы, или это не то?
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
07.03.2014, 12:07 #5
Ilot,
C++
1
2
std::streambuf * buf = std::cout.rdbuf();
std::ostream out(buf);
0
Ilot
Модератор
Эксперт С++
1823 / 1181 / 232
Регистрация: 16.05.2013
Сообщений: 3,118
Записей в блоге: 5
Завершенные тесты: 1
07.03.2014, 12:07  [ТС] #6
Цитата Сообщение от aLarman Посмотреть сообщение
или это не то?
Не то.
Есть класс:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
struct MyChar: public std::char_traits<char> {
    static bool
    eq(const char_type& __c1, const char_type& __c2)
    { return toupper(__c1) == toupper(__c2); }
 
    static bool
    lt(const char_type& __c1, const char_type& __c2)
    { return toupper(__c1) < toupper(__c2); }
    static int
    compare(const char_type* __s1, const char_type* __s2, size_t __n)
    { return memicmp(__s1, __s2, __n); }
    /*
    static const char_type*
    find(const char_type* __s, size_t __n, const char_type& __a)
    { return static_cast<const char_type*>(memchr(__s, __a, __n)); }
    */
};
 
//std::basic_ostream<char, MyChar> mcout;
typedef std::basic_string<char, MyChar> ci_string;
Надо сделать, что бы работало такое выражение:
C++
1
mcout << ci_string;
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
07.03.2014, 12:13 #7
aLarman, он хочет через Traits.

Добавлено через 5 минут
Да, кстати придется делать и свой streambuf.
0
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.03.2014, 12:41 #8
примерчик
1
Ilot
Модератор
Эксперт С++
1823 / 1181 / 232
Регистрация: 16.05.2013
Сообщений: 3,118
Записей в блоге: 5
Завершенные тесты: 1
07.03.2014, 14:53  [ТС] #9
Tulosba, благодарю, однако вывести в стандартный поток это не проблема. Сложно ли создать свой поток и связать его с консолью, раз такая возможность предусмотренна в стандартной библиотеке и как это сделать? Вот собственно в чем вопрос.
0
Tulosba
:)
Эксперт С++
4397 / 3233 / 297
Регистрация: 19.02.2013
Сообщений: 9,045
07.03.2014, 15:08 #10
Цитата Сообщение от Ilot Посмотреть сообщение
Сложно ли создать свой поток и связать его с консолью
Так ведь DrOffset всё написал уже выше.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
 
class mystream : public std::ostream
{
public:
    mystream()
    {
        rdbuf( std::cout.rdbuf() );
    }
};
 
int main() {
 
    mystream m;
    m << "Hello\n";
 
    return 0;
}
http://ideone.com/uvNq9M

Конструктор можно сделать даже так:
C++
1
mystream() : std::ostream( std::cout.rdbuf() ) { }
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
07.03.2014, 15:09 #11
Ilot, я ж говорю, наследуйся от basic_streambuf (если хочешь собственный Traits, то streambuf от stdcout не подойдет, т.к. привязан к его Traits).
0
Ilot
Модератор
Эксперт С++
1823 / 1181 / 232
Регистрация: 16.05.2013
Сообщений: 3,118
Записей в блоге: 5
Завершенные тесты: 1
11.03.2014, 14:49  [ТС] #12
Цитата Сообщение от DrOffset Посмотреть сообщение
Ilot, я ж говорю, наследуйся от basic_streambuf (если хочешь собственный Traits, то streambuf от stdcout не подойдет, т.к. привязан к его Traits).
Я знаю что cout не подойдет, поэтому и создал тему. Однако если файловый поток создать это как два пальца:
Кликните здесь для просмотра всего текста
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
#include <iostream>
#include <string.h>
#include <fstream>
struct MyChar: public std::char_traits<char> {
    static bool
    eq(const char_type& __c1, const char_type& __c2)
    { return toupper(__c1) == toupper(__c2); }
 
    static bool
    lt(const char_type& __c1, const char_type& __c2)
    { return toupper(__c1) < toupper(__c2); }
    static int
    compare(const char_type* __s1, const char_type* __s2, size_t __n)
    { return memicmp(__s1, __s2, __n); }
};
//std::basic_ostream<char, MyChar> mcout;
typedef std::basic_string<char, MyChar> ci_string;
int main()
{
    std::basic_ofstream<char, MyChar> mfout;
    mfout.open("C:\\rt.txt");
    ci_string str1("Masha");
    mfout << str1;
    return 0;
}

,то с созданием потока завязанного на консоль возникают определенные трудности. Понятно, что нужно создавать поток и передавать ему указатель на потоковый буфер, но вот так
C++
1
std::streambuf * buf = std::cout.rdbuf();
это сделать нельзя так как у меня должен быть буфер типа:
basic_streambuf<char, MyChar>
Интересно, а где создается объект cout? В заголовочниках нашел только:
C++
1
  extern ostream cout;
и ни одного намека на то где искать определение самого объекта.
Почитал немного о системном программировании в Win. Там пишут, что при создании консольного приложения для него создаются соответствующие потоки ввода/вывода. Другими словами выходит, что бы изменить поток вывода в консоль нужно юзать функции апи, а не стандартной библиотеки?
0
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
11.03.2014, 18:46 #13
Цитата Сообщение от Ilot Посмотреть сообщение
это сделать нельзя так как у меня должен быть буфер типа:
basic_streambuf<char, MyChar>
Так ведь я же и говорю, что нужно сделать свой streambuf, который бы соответствовал твоему traits.
Надо отнаследоваться от basic_streambuf<char, MyChar>, подробности можно посмотреть тут.

Цитата Сообщение от Ilot Посмотреть сообщение
Интересно, а где создается объект cout?
Внутри С++ runtime.

Добавлено через 18 минут
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
class console_buffer
    : public std::basic_streambuf<char, MyChar>
{
//......
};
 
int main()
{
    console_buffer conBuf;
    std::basic_ostream<char, MyChar> conOut(&conBuf);
 
    conOut << "test";
}
1
DrOffset
7377 / 4454 / 1009
Регистрация: 30.01.2014
Сообщений: 7,304
14.04.2014, 19:51 #14
Ilot,
Ну вот как-то так может выглядеть реализация:
Кликните здесь для просмотра всего текста
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
#include <streambuf>
#include <limits>
#include <cstdio>
 
class console_buffer
    : public std::basic_streambuf< char, std::char_traits<char> >
{
public:
    explicit console_buffer(FILE * file)
        : file_(file)
    {}
 
    ~console_buffer()
    {
        std::fflush(file_);
    }
 
protected:
    std::basic_streambuf<char, std::char_traits<char> > * setbuf(char * s, std::streamsize n)
    {
        size_t n_size_t = sizeof(std::streamsize) > sizeof(size_t)
                          ? static_cast<size_t>(
                                std::min(
                                    static_cast<std::streamsize>(std::numeric_limits<size_t>::max())
                                  , n
                                )
                            )
                          : static_cast<size_t>(n);
        std::setvbuf(file_, s, s == 0 && n == 0 ? _IONBF : _IOFBF, n_size_t);
        return this;
    }
 
    pos_type seekoff(off_type off
                     , std::ios_base::seekdir dir
                     , std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
    {
        int whence;
        switch(dir)
        {
        case std::ios_base::beg:
            whence = SEEK_SET;
            break;
        case std::ios_base::cur:
            whence = SEEK_CUR;
            break;
        case std::ios_base::end:
            whence = SEEK_END;
            break;
        default:
            return pos_type(-1);
        }
        if(off <= std::numeric_limits<off_type>::max() && std::fseek(file_, off, whence) == 0)
        {
            std::fpos_t pos;
            std::fgetpos(file_, &pos);
            return pos_type(pos);
        }
        return pos_type(-1);
    }
 
    pos_type seekpos(pos_type pos
                     , std::ios_base::openmode = std::ios_base::in | std::ios_base::out)
    {
        std::fpos_t p(pos);
        return std::fsetpos(file_, &p) == 0 ? pos : pos_type(-1);
    }
 
    int sync()
    {
        return std::fflush(file_) == 0 ? 0 : -1;
    }
 
    std::streamsize showmanyc()
    {
        return -1;
    }
 
    int_type overflow(int_type c = traits_type::eof())
    {
        if(c == traits_type::eof())
        {
            std::ptrdiff_t unwritten = this->pptr() - this->pbase();
            if(unwritten != 0)
            {
                std::fflush(file_);
                if(this->pptr() - this->pbase() < unwritten)
                {
                    return traits_type::not_eof(c);
                }
                return traits_type::eof();
            }
            return traits_type::not_eof(c);
        }
        else
        {
            int result = putc(c, file_);
            return result != EOF ? result : traits_type::eof();
        }
    }
 
private:
    FILE * file_;
};
 
#include <ostream>
 
int main()
{
    console_buffer conBuf(stdout);
    std::basic_ostream<char, std::char_traits<char> > conOut(&conBuf);
 
    conOut << "TeSt";
}
1
14.04.2014, 19:51
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.04.2014, 19:51
Привет! Вот еще темы с ответами:

Как создать свой символ - C++
Есть ли в С++ возможность создать свой символ (по точкам) и вывести его на консоль?

Как создать свой собственный тип на C++? - C++
Здравствуйте!!! Возник вопрос как создать свой собственный тип на С++ который включат такие типы как int, string, double?

Как создать виртуальный поток и переопределить оператор <<? - C++
Виртуальный то есть имеется ввиду не файловый и не строковый и не консольный. Впрочем, создание сего не противоречит синтаксису. Вот,...

Как создать свой архив, упаковывать и распаковывать? - C++
как создать свой архив упаковывать и распаковывать скиньте ссылки и коды примеров пожалуста :) на C++ с возможность...


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

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

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