быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695

При перекомпиляции сервера перекомпилируется клиент, а что, собственно в этом плохого?

04.03.2013, 12:54. Показов 4139. Ответов 38
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Друзья!
Начинаем цикл вопросов про COM- Объекты. Первый вопрос возник по статье Безверхова, вот здесь статья. Вот там такой пример:

C++
1
2
3
4
5
//myobj.cpp - реализация методов объекта сервера
#include "myobj.h"     
void Foo::SetA(int i){a = i;} 
void Foo::SetB(float f){b = f;} 
void Foo::SetAB(int i, float f){a = i; b = f;}
C++
1
2
3
4
5
6
7
8
9
//myobj.h - определение объекта Foo
class Foo { 
      private:     
                   int a;     float b;   
      public:     
                  void SetA(int i);     
                  void SetB(float f);     
                  void SetAB(int i, float f); 
      };
C++
1
2
3
4
5
6
7
//myclient.cpp - реализация кода клиента
#include "myobj.h"     
int main () {
    Foo Cls;   
    Cls.SetA(12); 
    Cls.SetB(13.2);
}
Видите ли вы здесь неудобство, которое при этом возникает? А неудобство-то вот какое - при компиляции сервера нам действительно нужно знать всё про класс - и про его данные и про его методы. А вот при компиляции клиента нас интересуют только методы - данные-то сервера нам недоступны. И если в процессе развития сервера мы, скажем, добавили в класс еще одну, сугубо внутреннюю, переменную или внутренний метод, то понятно, что нам нужно будет перекомпилировать сервер. Но ведь нам также придется и перекомпилировать клиент - файл myobj.h ведь изменился! А вот сам клиент - не изменялся. А перекомпилировать клиент - придётся...
А перекомпилировать клиент - придётся... А чё не так-то?
...Итак, компилим сервер:

Bash
1
g++ -c myobj.cpp
компилим клиент

Bash
1
g++ -c myclient.cpp
Лепим экзешник.
Bash
1
g++ -o myclient myclient.o myobj.o
Всё! Теперь ты хоть ЗАМЕНЯЙСЯ сервер, хоть чё сюда напиши:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Foo { 
      private:     
            
                   int a;     float b;   
      
      public:     
                  void SetA(int i);     
                  
                  void SetB(float f);     
 
                  //Можно эту функцию закомментить
                  //void SetAB(int i, float f); 
            
          //можно добавить функцию:
          void SetB();  
            
      };
Главное хидер не забудь поправить как надо. И всё. И НЕ НАДО перекомпилировать клиент, то есть не надо давать команду
Bash
1
g++ -c myclient.cpp
А то, что тебе придётся всё-таки линковать
Bash
1
g++ -o myclient myclient.o myobj.o
Так извините меня, сервер и клиент находятся в одном экзешнике. Или автор в претензиях, что мы меняя ЧАСТЬ экзешника (сервер) вынуждены менять ВЕСЬ экзешник? (При совместной компиляции те же рассуждения, там так же создаются *.o файлы, просто если мы совместно будем всё это компилить, мы два раза создадим АБСОЛЮТНО одинаковые файлы myclient.o, незачем два раза создавать одно и то же, да и раздельная компиляция прибавит наглядности.)

Я ничё не понимаю. Может кто-то разъяснит мне, что имел ввиду Безверхов, говоря:
А перекомпилировать клиент - придётся...
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
04.03.2013, 12:54
Ответы с готовыми решениями:

Как отключить клиент от сервера, не закрывая при этом приложения
Приветствую. Имеется 2 приложения сервер-клиент. При загрузке форму сервер запускается на прослушку из класса, отправка так-же из класса....

Запрет копирования с сервера на клиент при условии, что буфер обмена и маппинг дисков останутся включенными
Добрый день уважаемые форумчане !!! Вопрос не раз поднимался ... но хотел бы изложить свои мысли ... и попросить вашего мнения ... ...

Как узнать о том, что клиент дисконектнулся от сервера?
Здравствуйте. Делаю сервер. В нем есть подсчет пользователей онлайн. Прибавить пользователя, при подключении к сокету легко, но вот как...

38
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
05.03.2013, 14:30
Author24 — интернет-сервис помощи студентам
Цитата Сообщение от kravam Посмотреть сообщение
к чему относится этот пример
то ли вы меня не поймете то ли я вас. если вы задаете вопрос о COM-объектах, то вы можете менять сервер как угодно - переставлять поля местами, менять их количество, позиции и сигнатуры методов - клиенту это без разницы до тех пор пока интерфейс не изменяется. вы ведь возвращаете клиенту интерфейс.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
05.03.2013, 16:28  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
если вы задаете вопрос о COM-объектах
в том-то и дело, что не о СOM! Понимаете, Безверхов начинает объяснение COM-объектов издалека с языка C++. Так что имеем ввиду, щас речь идёт о C++. То есть имеем чистой воды класс и main, они ещё и не COM-объекты и таковыми после компиляции и не будут, они просто разнесены по разным файлам-сырцам.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
06.03.2013, 10:04
Цитата Сообщение от kravam Посмотреть сообщение
не о СOM
1 если у нас обычный объект, то необходимость компиляции при внесении изменений в определение класса очевидна: изменение набора полей или обработчиков, их типов или сигнатур должно быть учтено на клиенте. в противном случае у него просто будет неактуальные адреса данных или точки входа, неверные размеры данных или процедуры передачи аргументов.
2 если у нас "обычный" объект который не содержит полей, а состоит из одних чистых виртуальных функций причем их набор и сигнатуры фиксированы, то как бы мы не издевались над его реализацией (над объектом наследником) компиляция клиента нам не нужна - мы всегда работаем с известным интерфейсом. это и есть COM.
1
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
06.03.2013, 11:34  [ТС]
Ну, положим, первой части вполне хватило бы для ответа на вопрос, а вторая часть это то, чего не может быть

Цитата Сообщение от vxg Посмотреть сообщение
2 если у нас "обычный" объект который не содержит полей, а состоит из одних чистых виртуальных функций причем их набор и сигнатуры фиксированы, то как бы мы не издевались над его реализацией (над объектом наследником) компиляция клиента нам не нужна - мы всегда работаем с известным интерфейсом. это и есть COM.
И там дальше в статье по-моему речь и идёт об этом.
Не бывает хидера с таким описанием. (если, конечно мы ведём речь о C++ объектах. Ну то есть не выносим объект в отдельную dll). По-любому интерфейс наследника должен быть известен клиенту. Так что одним подключением абстрактного класса никак не обойтись.

Ну, вы наверное имели ввиду, что если мы исхитримся сделать так, то это значит, что мы и сконструировали тот самый настоящий COM-объект, который находится в другом исполняемом модуле и никак иначе.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
06.03.2013, 14:33
Цитата Сообщение от kravam Посмотреть сообщение
то, чего не может быть
чего не может быть? того что где-то живет нечто способное при вызове известной и неизменной функции вернуть указатель на объект класса содержащего одни чистые виртуальные функции (то есть интерфейс)? это вполне может быть. хоть в том же модуле хоть за его пределами. и это называется COM
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
07.03.2013, 01:24  [ТС]
Того не может быть, что:
нас "обычный" объект который не содержит полей, а состоит из одних чистых виртуальных функций причем их набор и сигнатуры фиксированы, то как бы мы не издевались над его реализацией (над объектом наследником) компиляция клиента нам не нужна - мы всегда работаем с известным интерфейсом. это и есть COM.
И чтобы этот объект был в одном исполняемом модуле, (том же экзешнике) вместе с клиентом.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
07.03.2013, 08:22
Цитата Сообщение от kravam Посмотреть сообщение
И чтобы этот объект был в одном исполняемом модуле
как раз сделать так что бы он был в одном исполняемом модуле человек может хоть на коленке. а вот сделать что бы он был в другом приложении - это заморочки с заглушками и маршаллингом. тоже конечно можно сделать свой педальный маршаллинг, но труд адов.
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
07.03.2013, 11:34  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
как раз сделать так что бы он был в одном исполняемом модуле человек может хоть на коленке
Сказать всё, что угодно можно. Сделайте...
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
10.03.2013, 03:23  [ТС]
Внесём ясность в обсуждаемый вопрос. Мы выяснили, что при изменении хидера всегда надо пересобирать клиент.

Не по теме:

Напоминаю, речь идёт исключительно о C++ коде, COM не трогаем. Я поторопился, задав вопрос в этом разделе- ну так значит не смог разобраться, пусть тему перенесут.


Всегда ли?

Эксперименты показали, что если клиент для доступа к данным будет пользоваться исключительно функциями-методами, тогда пересобирать его необязательно!

Действительно, возьмём этот код, добавим в сервер функцию-метод (в хидер и в*.cpp)
C++
1
void funktsia () {;}
и добавим её вызов в клиент:
C++
1
w.funktsia ();
скомпилим клиент
Bash
1
g++ -c client.cpp
посмотрим символы, которые в client.o
Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nm -u client.o
 
         U __Unwind_Resume
         
         //Вот она, наша функция
         U __ZN5world8funktsiaEv
         
         U __ZN5worldC1Ev
         U __ZNSolsEPFRSoS_E
         U __ZNSsD1Ev
         U __ZNSt8ios_base4InitC1Ev
         U __ZNSt8ios_base4InitD1Ev
         U __ZSt4cout
         U __ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
         U __ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
         U __ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4
_S5_T1_E
         U ___gxx_personality_v0
         U ___main
         U _atexit
Теперь соберём сервер и посмотрим его нутро:

Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
nm server.o
 
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 d .gcc_except_table
00000000 r .rdata
00000000 t .text
         U __Unwind_Resume
 
//Вот она, наша функция
0000007a T __ZN5world8funktsiaEv
 
 
00000000 T __ZN5worldC1Ev
00000000 T __ZN5worldC2Ev
         U __ZNSsC1Ev
         U __ZNSsD1Ev
         U __ZNSsaSEPKc
         U ___gxx_personality_v0
И вы знаете, ребята, есть у меня такое ощущение, что линковщик, ища соответствие между символом
__ZN5world8funktsiaEv из client.o ни с чем не перепутает __ZN5world8funktsiaEv из server.o

Почему же линковщик может перепутать поля класса?

На самом деле ответ прост, и он лежит на повержности. Все, кто отписался, его знают. А вот мне пришлось чуток подумать. В server.o генерируется код, который кладёт в первое поле world значение такое-то, а во второе такое-то. А в клиенте вынимаются значения из полей- из первого и второго. Если в хидере поменяются их имена, и клиент не узнает об этом на этапе компиляции, он не узнает этого никогда. Так и будет действовать, как запрограммирован при первой компиляции.

Вернёмся с функциями, с ними всё проще.
В коде они ведут себя как НЕ методы класса- то есть принадлежность к классу абсолютно никак не выявляется. (В объекте даже указателя на них нет. Был бы- не исключалась бы возможность путаницы, как с полями) Выясните размер world- он будет равен 8, по 4 байта накаждое поле string. Просто функция-метод (и конструктор) принимает указатель на объект класса и работает с ним. Все об этом знают, просто написать забыли.

Ну вот и всё, собсно. То есть если пользуетесь для доступа к данным исключительно функциями, можете смело менять хидер и не трогать сырец с main. Всякое несоответствие (если таковое найдётся) между вызовами функций и тем, как они представлены в классе, выявится на этапе линковки. А не выявится, значит экзешник отработает корректно.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
11.03.2013, 11:25
Цитата Сообщение от kravam Посмотреть сообщение
Ну вот и всё, собсно
нет, вы не совсем правы. сейчас приведу пример.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
11.03.2013, 11:34
итак, делаем игрушечный интерфейс и игрушечную библиотеку COM.
имеем заголовочный файл в котором есть:
- определение класса my_iface с чистыми виртуальными функциями f1 и f2 - это наш игрушечный интерфейс
- прототип функции create_obj возвращающей указатель на объект класса my_iface - это наша игрушечная библиотека COM (наш аналог функции CoCreateInstance).
собираем DLL в которой есть класс реализующий интерфейс и есть функция возвращающая указатель на реализацию.
подключаем DLL к проекту.
если в заголовочном файле в определении класса поменять местами виртуальные функции f1 и f2, то при вызове obj->f1() мы ничуть не удивившись обнаружим на экране информацию говорящую о том, что реально была вызвана функция f2.
Вложения
Тип файла: rar my_iface_test.rar (117.2 Кб, 16 просмотров)
1
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
11.03.2013, 11:38
с вызовами функций не являющимися виртуальными таких эффектов не будет, но учитывая тот факт, что в нормальных классах деструктор является виртуальным перекомпиляция нужна всегда.
0
11.03.2013, 11:45

Не по теме:

Цитата Сообщение от vxg Посмотреть сообщение
что в нормальных классах деструктор является виртуальным
ну если наследники не нужны, это не значит что класс не нормальный.

0
11.03.2013, 11:48

Не по теме:

Цитата Сообщение от Tulosba Посмотреть сообщение
ну если наследники не нужны, это не значит что класс не нормальный
его ненормальность проявится когда кому-нибудь взбредет от него наследовать

0
11.03.2013, 11:54

Не по теме:

Цитата Сообщение от vxg Посмотреть сообщение
его ненормальность проявится когда кому-нибудь взбредет от него наследовать
Неумение пользоваться имеющимися классами (в частности попытки наследоваться от тех классов, которые для этого не предназначены) вовсе не значит, что класс написан неправильно. Возьмите хотя бы std::string.
В шарпике есть например sealed, четко говорящий о том, что наследование запрещено. В плюсах же приходится немного углубляться в документацию.

0
11.03.2013, 12:07

Не по теме:

Цитата Сообщение от Tulosba Посмотреть сообщение
Неумение
безусловно все из-за него, родимого. никто не говорил "неправильно". говорил "ненормально" в плане отсутствия у проектировщика класса желания исключить потенциальную возможность утечки памяти или ошибки доступа. в любом случае данная дискуссия не относится к вопросу, имеет черты религиозной и на мой взгляд продолжать ее в данной теме нежелательно.

1
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
11.03.2013, 12:59  [ТС]
Цитата Сообщение от vxg Посмотреть сообщение
если в заголовочном файле в определении класса поменять местами виртуальные функции f1 и f2
Угу, только я разделил для себя:

1)использование абстрактного класса это одна история- ваш пример,
2)неиспользование абстрактного класса- другая история.

Сейчас мы говорим о втором примере. Никаких абстрактных классов! Мне почему-то казалось это очевидным, раз не оговорено обратное .

Что касается вашего примера, то я вчера долго думал над ним и пришёл к тому же выводу, что и вы. Создал даже тему в разделе C++ потому, что к COM это пока никаким боком. Я и эту-то поторопился в этом разделе создавать.

Программа взаимодействует с классом исключительно через интерфейс. Однажды класс меняется и меняется его хидер. Надо ли перекомпилировать всю программ

вот оттуда моя цитата:
Ага, значит при компиляции мы привязаны к абстрактному классу. Один определённый вывод есть, то есть при измененеии абстрактного класса, надо перекомпилировать и main.o
Ну опять же в названии темы нет "абстрактный класс", моя вина. Но я оговариваю всё подробно в первом же посте.
0
Модератор
 Аватар для vxg
3402 / 2173 / 353
Регистрация: 13.01.2012
Сообщений: 8,430
11.03.2013, 13:13
а с чего вообще сыр-бор кроме интереса "а что же внутри". что внутри выяснили. какой еще вопрос то?
0
быдлокодер
 Аватар для kravam
1724 / 911 / 106
Регистрация: 04.06.2008
Сообщений: 5,695
11.03.2013, 13:16  [ТС]
Вопрос "что внутри" это следствие вопроса "надо ли перекомпилировать", а так всё, никакого больше.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
11.03.2013, 13:16
Помогаю со студенческими работами здесь

Проверка на стороне сервера, что клиент обработал отправленные данные
Есть клиент и есть сервер, общаются по именованому каналу (named pipe) Проблема: нужно сделать так чтобы сервер после записи данных в...

Зависает клиент при приёме от сервера
С начало сделал посыл данных только от клиента серверу..там всё хорошо далее начал делать обратный, от сервера вроде как всё хорошо...

Как загрузить файл с сервера по ссылке, при этом переименовав его
Есть ссылка на скачивание файла с сервера: <a class="link_more_cont" target="_blank"...

Чем пользоваться при создании клиент-сервера?
День добрый! Есть определенная программа. Работают в ней одновременно до 5 пользователей. В данный момент она представляет из себя...

Тормоза При Перекомпиляции Бд
Собственно что есть БД на серваке, запускаем перекомпиляцию - 1 шаг (20-30сек) - 2 шаг (20-30минут) Копируем эту же базу в...


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

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

Новые блоги и статьи
Создаем RESTful API с Laravel
Jason-Webb 28.04.2025
REST (Representational State Transfer) — это архитектурный стиль, который определяет набор принципов для создания веб-сервисов. Этот подход к построению API стал стандартом де-факто в современной. . .
Дженерики в C# - продвинутые техники
stackOverflow 28.04.2025
История дженериков началась с простой идеи — создать механизм для разработки типобезопасного кода без потери производительности. До их появления программисты использовали неуклюжие преобразования. . .
Тестирование в Python: PyTest, Mock и лучшие практики TDD
py-thonny 28.04.2025
Тестирование кода играет весомую роль в жизненном цикле разработки программного обеспечения. Для разработчиков Python существует богатый выбор инструментов, позволяющих создавать надёжные и. . .
Работа с PDF в Java с iText
Javaican 28.04.2025
Среди всех форматов PDF (Portable Document Format) заслуженно занимает особое место. Этот формат, созданный компанией Adobe, превратился в универсальный стандарт для обмена документами, не зависящий. . .
Динамические массивы в C++ - создание и использование
NullReferenced 27.04.2025
Динамические массивы представляют собой один из фундаментальных инструментов программирования на C++, позволяющий создавать структуры данных, размер которых определяется во время выполнения. . .
Асинхронный JavaScript: Промисы, Async/Await и Fetch API
Reangularity 27.04.2025
Пользователь заходит на веб-страницу, нажимает кнопку и. . . ничего не происходит. Сайт словно замер. Через несколько секунд всё внезапно оживает, но пользователь уже успел закрыть вкладку. Знакомая. . .
Management on GitLab and repository management in Visual Studio code
jigi33 27.04.2025
- repo management on GitLab - CI/ CD in GitLab - VCS repository management in Visual Studio code (see attachments)
Kanban или Scrum - что выбрать?
EggHead 27.04.2025
Kanban и Scrum — уже много лет удерживают лидирующие позиции среди гибких подходов. Руководители проектов и команды разработчиков то и дело сталкиваются с дилеммой: какой из этих двух методов выбрать. . .
Кастомные Middleware на C# в ASP.NET Core
UnmanagedCoder 27.04.2025
Разработка веб-приложений сегодня мало напоминает монолитное программирование прошлых лет. На смену громоздким блокам кода пришла модульная архитектура, где каждый компонент выполняет строго. . .
Анализ и линтинг кода JavaScript: ESLint, Prettier и JSHint
run.dev 26.04.2025
JavaScript прошёл долгий путь от простого языка для анимации веб-страниц до основы современной веб-разработки. С ростом сложности приложений, увеличением кодовых баз и масштабированием команд. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru