LINUX.ORG.RU

GTK C *_new functions returning GtkWidgets

 


0

2

Я нашел вот такую цитату:

https://book.huihoo.com/gtk+-gnome-application-development/cha-gtk.html

All of the _new() routines return a GtkWidget*, even though they allocate a subclass; this is for convenience.

И это действительно так, например gtk_search_bar_new() возвращает не GtkSearchBar* а GtkWidget*:

https://developer.gnome.org/gtk3/stable/GtkSearchBar.html#gtk-search-bar-new

Хотя eсли что-то не наследуется от GtkWidget, getter'ы, «newer'ы» уже возвращают указатель на то, что нужно например:

Далее, глядя на код gedit я вижу, что внутри *Private структур для класс GtkWidget* хранятся редко, чаще конкретные типы.

В коде, с которым я имею дело вообще бардак. Часть *_new() функций возвращает GtkWidget*, часть наследника. Внутри части *Private, часть лежит как GtkWidget* часть как SomethingDerivedFromGtkWidget*.

Я хочу навести в этом порядок, не переча конвенциям Gtk. Отсюда пару вопросов:

  1. Что за удобство такое возвращать base класс из «конструкторa»?
  2. Имеет ли смысл в своем коде возвращать GtkWidget* в my_derived_from_gtk_widget_new() или в не библиотечном коде все же лучше вернуть MyDerivedFromGtkWidget*?
  3. Какое такое удобство хранить widget'ы как GtkWidget* в *Private, это ведь сильно снижает читаемость - непонятно, что там действительно лежит. Отсутствие необходимости кастов когда это что-то передается например в gtk_container_add? Но ведь касты и так приходится добавлять в обратную сторону делая что-то вроде my_code_do_smth_with_my_derived_from_gtk_widget ((MY_DERIVED_FROM_GTK_WIGET_CLASS(widget_pointer)

У меня есть несколько опций: везде возвращать GtkWidget* и хранить как GtkWidget в *Private; везде возвращать GtkWidget* и хранить как Derived* в *Private; и возвращать и хранить Derived*. IMHO третье наиболее логично, несмотря на конценции GTK. Кто-то может прояснить жтот вопрос?

возвращать и хранить Derived*

и не парься.

fsb4000 ★★★★★
()

Что за удобство такое возвращать base класс из «конструкторa»?

Тот самый ООПшный полиморфизм.

hobbit ★★★★★
()

Какие нафиг классы и наследники? Это ж сишечка. Возвращается всегда указатель на структуру, у него класса нет, это просто адрес в памяти, указывающий на какую-то байду. А быть эта байда может и жнецом, и игрецом, и на дуде игрецом; структуры в сишечке не наследуются, посему тип один на всё многообразие «классов». В гутакэ специально накостыляли макросы для «приведения типов», которые чекают, что по данному указателю лежит, то это или не то, что ты имел в виду. Причём ты можешь их не юзать и пихать напрямую одни и те же указатели во все функции с аргументами совместимых типов. Работать будет так же, но вот если сломается — без этих макросов придётся долго и муторно дебажить, чтобы понять, где зрада.

Moondancer
()

Ну имхо они на статистике свои конвенции основывали.
Т.е., если ты создал виджет, то с вероятностью близкой к 100% ты его положишь в контейнер => каст на GtkWidget тебе нужен, и вот он, держи его.
А вот дальше... будешь ли ты вызывать методы MyDerivedFromGtkWidget, либо методы кого-то между GtkWidget и MyDerivedFromGtkWidget по цепочке наследования — тут бабка надвое сказала.
С ненулевой вероятностью ты просто повесишь callback и все, не сохраняя указатель и не вызывая методы на месте.

Имхо следует придерживаться конвенции возврата GtkWidget, чтобы интерфейсы были однотипные везде. Этакий Coding Style.

А вот у себя в private для удобства вполне можно хранить указатель на тип, методы которого чаще дергаешь. Т.е. вариант 2.
Либо, если дергаешь разные методы, то вариант 1.

Tayler ★★
()
Ответ на: комментарий от Tayler

@Tayler: Вот я тоже так, подумал, везде в GTK все, что наследуется от GtkWidget* возвращает GtkWidget*, например gtk_source_view_new(), gtk_box_new(), да все, что угодно.

Я так и понял, что из-за того, что нету в GTK implicit upcast'a. С другой стороны если в *Private одни GtkWidget*-ы - читаемость стремится к нулю.

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 1)
Ответ на: комментарий от Moondancer

@Moondancer: все, что ты сказал правда, но никак не относится к вопросу, который я задал. Посмотри документацию Gtk и «конструктры» «классов» «наследующих» од GtkWidget*. *Private это отдельная структура, где хранятся приватные данные «класса». То, что это все основано на макросах и хаках (хранению struct Parent внутри struct Derived) не мешает ему быть OOP и иметь конвенции.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

А если честно, то я бы сам с удовольствием, что-то по этому поводу почитал. ;)

Ответ Tayler'а меня устраивает, но я все же для читаемости перелопачу немного код, с которым имею дело, т.е.:

  1. Пусть то, что наследует от GtkWidget* в blabla_ew() возвращает GtkWidget* а не Blabla*, раз уж такая конвенция (выросшая из отсутствия implicit upcast'а)
  2. Пусть все, что лежит в *Private будет скастовано на Blabla*, тогд открывая *Private будет сразу виден layout данного конкретного виджета (оверлеи в нем там внутри, вбоксы или еще чего)

Причем p2 это лично мое наблюдение, что когда в коде

struct BlablaPrivate {
    GtkWidget *right_widget;
    GtkWidget *left_widget;
    GtkWidget *cool_widget;
    GtkWidget *some_bar_widget;
    GtkWidget *yet_another_widget;
}

то читающий эту муть будет долго разбираться куда ему тут добавить overlay и revealer, чтобы прикрутить еще один выезжающий виджет со свистелками и перделками.

dissident ★★
() автор топика
Последнее исправление: dissident (всего исправлений: 1)
Ответ на: комментарий от KivApple

Код уже написан, не мной, я в нем баги правлю и фичи добавляю, так как сам этой десткой игрушкой пользуюсь, а поскольку мой фичер реквест висел там года 4, пришлось сделать самому.

dissident ★★
() автор топика
Ответ на: комментарий от dissident

Не, про это я в курсе. Я имел в виду, есть ли какие-то руководства по гтк-шному ООПу? Какие они накрутили макросы и для чего они используются?

Deleted
()
Ответ на: комментарий от Deleted

Думаю где-то тут: https://developer.gnome.org/gobject/stable/gtype-conventions.html или тут https://developer.gnome.org/gobject/stable/ и в других доках на developer.gnome.org. Гугли GObject site:developer.gnome.org. Документация действительно хорошая, но немножко плохо структурирована, чатиь там часть тут.

@Moondancer: ты знаешь, что первый компилятор С with classes (CFront) генерировал C code? Ты знаешь, что Vala генерирует C код? В тюринг-полном языке (как шаблоны например) в C++ на них можно сделать все, вот хотя бы https://www.youtube.com/watch?v=PJwd4JLYJJY. Это сумасшествие, но это возможно.

А если еще учесть, что OOP вообще должно умереть:

А GObject вполне семе mature объектно-онриентированная модель с reference counting (прямо как в C#) и даже кажеся с gargabe collection в случае cyclic refernce? Здесь могу ошибаться.

Не надо приписывать тупиковой ветви развиия науки computer science (OOP) какие-то вещи, которых в ней нет. Эта ерунда (диаграммы наследования и прочая родом из времен SQL хиерархичность можно релизовать не чем угодно. А настоящего OOP и в Java нет, посмотрите вот эти видео:

Кроме того, в GTK они использовали libffi (http://sourceware.org/libffi/), чтобы использовать свою объектуню моделья ЛЮБОМ языке. И посмотри сколько binding'ов для GKT? Объектно, там необьъектно, какая разница? Эта объектность ничего не кому ни дела и не выполнила ни одно обещания: https://www.dreamsongs.com/Files/ObjectsHaveFailedSlides.pdf. Какая разница на чем реализовывать это?

Лично меня это поражает и восхищает (написание regexp/json парсера в compile-time). Не знаю, кому это нужно, но звучит мозгораздирающе. А разговоры о том, что это сишечка, в ней можно вернуть тольку указатель на структуру, а в структуре хоть жнец, хоть игрец, да, в C type system слабее, но у тебя не получится сделать так:

struct X {
};

void f(struct Y*);
f(&X);

Разве что я совсем не знаю C.

PS Не надо сужать глаза, вешая на них шоры.

dissident ★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.