Задать вопрос
Контакты

Достижения

Все достижения (3)

Наибольший вклад в теги

Все теги (35)

Лучшие ответы пользователя

Все ответы (75)
  • Как C++ обращаться из статического метода к нестатическим текущего класса?

    @monah_tuk
    Коротко: никак.

    Чуть более развёрнуто:
    статический метод класса практически не отличается от простой свободной функции. Отсюда наводка: если showDepFormCreate() будет просто свободной функцией, что будет вкладываться в понятие текущий класс? Так что или передавать инстанс или создавать внутри, зависит от того, что вам нужно. Хотя, чует моё сердце, что-то вы не так делаете.
    Ответ написан
    Комментировать
  • Как определить "качество видео" через ffmpeg?

    @monah_tuk
    ffmpeg -i lightning-timezones.mkv
    Guessed Channel Layout for  Input Stream #0.1 : stereo
    Input #0, matroska,webm, from 'lightning-timezones.mkv':
      Metadata:
        ENCODER         : Lavf56.15.102
      Duration: 00:02:21.61, start: 0.067000, bitrate: 442 kb/s
        Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, 1920x1080, SAR 1:1 DAR 16:9, 29.97 fps, 29.97 tbr, 1k tbn, 59.94 tbc (default)
        Metadata:
          ENCODER         : Lavc56.13.100 libx264
        Stream #0:1: Audio: pcm_s16le, 48000 Hz, 2 channels, s16, 1536 kb/s (default)


    конкретно:
    Stream #0:0: Video: h264 (High 4:4:4 Predictive), yuv444p, **1920x1080**, SAR 1:1 DAR 16:9, **29.97** fps, 29.97 tbr, 1k tbn, 59.94 tbc (default)


    Выделенное **ITEM**, первое разрешение, второе - FPS, DAR - Display Aspect Ratio - соотношение сторон картинки (подробнее про SAR, DAR, PAR: https://en.wikipedia.org/wiki/Pixel_aspect_ratio).

    144p это не качество, а кодировка разрешения: 176×144 прогрессивная развёртка. Я могу вам сделать 1080p такого отвратительного вида, что вас тошнить будет от одного воспоминания. Обычно такой вид используется для представления разрешения по низкой стороне, а p или i после - прогрессивная или межстрочная развёртка (прогрессивная - полный кадр, FPS 1:1, межстрочная - в каждом кадре два (в теоретически и больше) полукадра, которые потом хитрыми алгоритмами восстанавливаются до полного кадра, чем увеличивают FPS на выходе в 2 раза). Одно такое кодирование может скрывать несколько разрешений, к примеру: 1080p это и 1920x1080 и 1440x1080, в обоих случаях DAR 16:9, а вот SAR в первом случае 1:1, а во втором 1.33:1. Или 720p, помимо популярного 1280x720 (DAR 16:9, SAR 1:1), это может быть 960x720 при DAR 4:3 и SAR 1:1 или, так же 960x720 при DAR 16:9 и SAR 1.33:1

    Забыл написать про ffprobe - используйте его. Если есть ffmpeg, есть и он:
    ffprobe -v 0 -select_streams v -print_format flat -show_format -show_streams /home/alexd/thunderbird-timezones-fix.mkv

    в качестве параметров "-print_format" можете указывать: flat, json, xml, csv, compact, ini - что вам покажется удобнее. "-select_streams" позволяет выбрать стримы по любому критерию, поддерживаемому ffmpeg: v - video, a - audio, # - по номеру и т.д. Пример выхлопа:
    streams.stream.0.index=0
    streams.stream.0.codec_name="h264"
    streams.stream.0.codec_long_name="H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"
    streams.stream.0.profile="High 4:4:4 Predictive"
    streams.stream.0.codec_type="video"
    streams.stream.0.codec_time_base="1001/60000"
    streams.stream.0.codec_tag_string="[0][0][0][0]"
    streams.stream.0.codec_tag="0x0000"
    streams.stream.0.width=640
    streams.stream.0.height=480
    streams.stream.0.coded_width=640
    streams.stream.0.coded_height=480
    streams.stream.0.has_b_frames=2
    streams.stream.0.sample_aspect_ratio="1:1"
    streams.stream.0.display_aspect_ratio="4:3"
    streams.stream.0.pix_fmt="yuv444p"
    streams.stream.0.level=30
    streams.stream.0.color_range="N/A"
    streams.stream.0.color_space="unknown"
    streams.stream.0.color_transfer="unknown"
    streams.stream.0.color_primaries="unknown"
    streams.stream.0.chroma_location="left"
    streams.stream.0.timecode="N/A"
    streams.stream.0.refs=4
    streams.stream.0.is_avc="1"
    streams.stream.0.nal_length_size="4"
    streams.stream.0.id="N/A"
    streams.stream.0.r_frame_rate="30000/1001"
    streams.stream.0.avg_frame_rate="30000/1001"
    streams.stream.0.time_base="1/1000"
    streams.stream.0.start_pts=67
    streams.stream.0.start_time="0.067000"
    streams.stream.0.duration_ts="N/A"
    streams.stream.0.duration="N/A"
    streams.stream.0.bit_rate="N/A"
    streams.stream.0.max_bit_rate="N/A"
    streams.stream.0.bits_per_raw_sample="8"
    streams.stream.0.nb_frames="N/A"
    streams.stream.0.nb_read_frames="N/A"
    streams.stream.0.nb_read_packets="N/A"
    streams.stream.0.disposition.default=1
    streams.stream.0.disposition.dub=0
    streams.stream.0.disposition.original=0
    streams.stream.0.disposition.comment=0
    streams.stream.0.disposition.lyrics=0
    streams.stream.0.disposition.karaoke=0
    streams.stream.0.disposition.forced=0
    streams.stream.0.disposition.hearing_impaired=0
    streams.stream.0.disposition.visual_impaired=0
    streams.stream.0.disposition.clean_effects=0
    streams.stream.0.disposition.attached_pic=0
    streams.stream.0.tags.ENCODER="Lavc56.13.100 libx264"
    format.filename="/home/alexd/thunderbird-timezones-fix.mkv"
    format.nb_streams=1
    format.nb_programs=0
    format.format_name="matroska,webm"
    format.format_long_name="Matroska / WebM"
    format.start_time="0.067000"
    format.duration="84.451000"
    format.size="80212"
    format.bit_rate="7598"
    format.probe_score=100
    format.tags.ENCODER="Lavf56.15.102"
    Ответ написан
    1 комментарий
  • Как обнулить std::cin и заставить его ждать ввода?

    @monah_tuk
    Входная программа завершила писать и ваша получила EOF. Всё, баста карапузики. Проверяйте статус ввода и завершайтесь - больше вы данных не получите, никогда и ни при каких условиях.

    Не верите? Отправьте на stdin не одну строку, а файл: выведется правильно файл, а потом посыпят пустые строки или последний токен - зависит от реализации.

    Обратите внимание на слово токен - у вас разделение по пробелу будет. Что бы читать строку, используйте std::getline().

    За флагами:
    www.cplusplus.com/reference/ios/ios/eof
    www.cplusplus.com/reference/ios/ios/fail
    www.cplusplus.com/reference/ios/ios/bad

    Ну а ваш код, по сути, должен стать таким:
    while (true) {
            std::getline(std::cin, line);
            if (!std::cin)
                break;
            std::cout << "out: " + line << std::endl;
        }


    обратите внимание, что если вы сделаете так:
    while (std::cin) {
            std::getline(std::cin, line);
            std::cout << "out: " + line << std::endl;
        }


    то вроде короче, и вроде работает, но будете постоянно выводить одну лишнюю строку (пустую или нет - от реализации), так что поверить статус стоит перед процессингом того, что получили.
    Ответ написан
    6 комментариев
  • Преимущество дружественных функций?

    @monah_tuk
    Когда нужно обеспечить некий доступ к внутрянке, при этом не выставляя её полностью наружу. Функция же может быть определена пользователем. Тем самым мы можем несколько повлиять на логику класса, не изменяя его интерфейсов и не вмешиваясь в бинарный код. Где такое может пригодиться? На вскидку:
    1. Юнит-тестирование
    2. При определении операторов (особенно всяких сложений, вычитаний)
    3. Собственно, изменение, в определённых пределах, поведения класса без наследования (но можно получить палкой, когда внутренняя структура поменяется).

    Но вообще, как это не гуглится? Гуглится!

    1. www.cprogramming.com/tutorial/friends.html последний абзац:
    friend and Encapsulation
    Some people believe that the idea of having friend classes violates the principle of encapsulation because it means that one class can get at the internals of another. One way to think about this, however, is that friend is simply part of a class's overall interface that it shows the world. Just like an elevator repairman has access to a different interface than an elevator rider, some classes or functions require expanded access to the internals of another class. Moreover, using friend allows a class to present a more restrictive interface to the outside world by hiding more details than may be needed by anything but the friends of the class.

    Finally, friends are particularly common in cases of operator overloading because it is often necessary for an overloaded operator to have access to the internals of the classes that are arguments to the operator.


    2. www.cplusplus.com/doc/tutorial/inheritance
    Typical use cases of friend functions are operations that are conducted between two different classes accessing private or protected members of both.


    3. stackoverflow.com/questions/17434/when-should-you-...

    В остальном, если что-то можно сделать без френдов - сделайте без них.
    Ответ написан
    1 комментарий
  • Как передать и проверить много параметров функции?

    @monah_tuk
    Дополню камрада ManWithBear

    Не нужно структуру отдельно переделывать в класс. Это и так класс, только доступ по-умолчанию public. И метод проверки можно не добавлять, а сделать внешним по отношению к структуре. Свободные функции не всегда плохо. Плюсы такого подхода в том, что memory-layout будет предсказуемый, а если в структуре нет non-POD типов то они останутся POD типами.

    Т.е. получится что-то вроде такого:
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    struct Point
    {
      int x;
      int y;
    };
    inline bool is_valid(const Point& p)
    {
      bool result = true;
      // some checks
      return result;
    }
    
    struct Rect : Point
    {
      int width;
      int height;
    };
    inline bool is_valid(const Rect& r)
    {
      bool result = is_valid(static_cast<const Point&>(r)) && r.width > 0 && r.height > 0;
      return result;
    }
    
    int main() {
    	// теряется возможность делать так:
    	//Rect r = {0, 1, 2, 3};
    	Rect r{};
    	r.x = 0;
    	r.y = 1;
    	r.width  = 10;
    	r.height = 11;
    	
    	auto check = is_valid(r);
    	
    	cout << " x=" << r.x
    	     << " y=" << r.y
    	     << " w=" << r.width
    	     << " h=" << r.height
    	     << " valid=" << check
    	     << endl;
    	
    	cout << sizeof(Rect) << "/" << sizeof(int)*4 << endl;
    	
    	uint8_t *ptr = reinterpret_cast<uint8_t*>(&r);
    	auto beg = ptr;
    	auto end = ptr + sizeof(Rect);
    	for (auto it = beg; it != end; ++it) {
    		cout << hex << setfill('0') << setw(2) << (int)*it << " ";
    	}
    	cout << endl;
    	
    	return 0;
    }


    Можно функцию проверки сделать и методом класса/структуры и, при этом, не виртуальной. Тогда проверка будет вызываться только в соответствии с типом. Тогда можно обойтись без static_cast, получится что-то вроде:
    #include <iostream>
    #include <iomanip>
    using namespace std;
    
    struct Point
    {
      int x;
      int y;
      
      bool is_valid() const
      {
      	bool result = true;
      	// some checks
      	return result;
      }
    };
    
    struct Rect : Point
    {
      int width;
      int height;
    
      bool is_valid() const
      {
      	bool result = Point::is_valid() && width > 0 && height > 0;
      	return result;
      }
    };
    
    void pass_point(const Point &p)
    {
    	cout << "point is valid: " << p.is_valid() << endl;
    }
    
    int main() {
    	// теряется возможность делать так:
    	//Rect r = {0, 1, 2, 3};
    	Rect r{};
    	r.x = 0;
    	r.y = 1;
    	r.width  = 0; // make invalid
    	r.height = 11;
    	
    	auto check = r.is_valid();
    	
    	cout << " x=" << r.x
    	     << " y=" << r.y
    	     << " w=" << r.width
    	     << " h=" << r.height
    	     << " valid=" << check
    	     << endl;
        
        // но следующий вызов скажет что точка валидна:
        // вызов валиден, т.к. Rect отнаследован от Point
        pass_point(r);
    	
    	cout << sizeof(Rect) << "/" << sizeof(int)*4 << endl;
    	
    	uint8_t *ptr = reinterpret_cast<uint8_t*>(&r);
    	auto beg = ptr;
    	auto end = ptr + sizeof(Rect);
    	for (auto it = beg; it != end; ++it) {
    		cout << hex << setfill('0') << setw(2) << (int)*it << " ";
    	}
    	cout << endl;
    	
    	return 0;
    }


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

Лучшие вопросы пользователя

Все вопросы (3)