CLASHA - Объектно-ориентированное программирование на Си

Использование и разработка софта (преимущественно на ПЦ)

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

CLASHA - Объектно-ориентированное программирование на Си

Post by Shaos »

Самые последние исходники CLASHA с примерами брать тут а обсуждение начинать читать отсюда (12 октября 2014)...

Задумался я о том, можно ли на голом Си покрыть всё разнообразие возможностей объектно-ориентированного программирования, которое даёт Си++. Например мой простой стиль C++ программирования легко переводится в C, но что делать с непростыми стилями? Начнём с простого - имеем вот такой код на C++:

Code: Select all

class MyClass
{
 int id;
 char str[10];
public:
 MyClass(){*str=0;id=0;}
 MyClass(char* s, int i=0);
~MyClass(){};
 void Print();
};

MyClass::MyClass(char *s, int i)
{
 id = i;
 strncpy(str,s,10);
 str[9] = 0;
}

void MyClass::Print()
{
 printf("id=%i str='%s'\n",id,str);
}
На голом C это можно записать так:

Code: Select all

typedef struct _MyClass
{
 int id;
 char str[10];
} MyClass;

void MyClass_cons(MyClass* this)
{
 *this->str = 0;
 this->id = 0;
} 

void MyClass_cons1(MyClass* this, char* s)
{
 MyClass_cons(this);
 strncpy(this->str,s,10);
 str[9] = 0;
}

void MyClass_cons2(MyClass* this, char* s, int i)
{
 MyClass_cons1(this,s); 
 this->id = i;
}

void MyClass_dest(MyClass* this)
{
}

void MyClass_Print(MyClass* this)
{
 printf("id=%i str='%s'\n",this->id,this->str);
}
А теперь подумаем как нам таким способом изобразить трёх котов ООП - инкапсуляцию, наследование и полиморфизм...
Last edited by Shaos on 17 Oct 2014 14:09, edited 4 times in total.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

В вышеприведённом примере полиморфизмом и не пахнет, т.к. мы используем разные функции для замены конструкторов с разным набором аргументов. Вот что получится если заюзать stdarg.h:

Code: Select all

typedef struct _MyClass
{
 int id;
 char str[10];
} MyClass;

void MyClass_cons(MyClass* this, int t, ...)
{
 va_list a;
 va_start(a,t);
 if(t>=0)
 {
    *this->str = 0;
    this->id = 0;
 }
 if(t>=1)
 {    
    strncpy(this->str,va_arg(a,char*),10);
    this->str[9] = 0;
 }
 if(t>=2)
 {    
    this->id = va_arg(a,int);
 }
 va_end(a);
}

void MyClass_dest(MyClass* this)
{
}

void MyClass_Print(MyClass* this)
{
 printf("id=%i str='%s'\n",this->id,this->str);
} 
Тут мы воспользовались неким дополнительным аргументом t, который говорит функции-конструктору о том, какой набор аргументов следует использовать. Для простоты можно завести набор дефайнов для этого "конструктора":

Code: Select all

#define MY_CLASS_VOID 0
#define MY_CLASS_CHARP 1
#define MY_CLASS_CHARP_INT 2
Пример кода, использующий этот "класс":

Code: Select all

MyClass obj,*pobj;

MyClass_cons(&obj,MY_CLASS_CHARP,"test");
MyClass_Print(&obj);
MyClass_dest(&obj);

pobj = (MyClass*)malloc(sizeof(MyClass));
MyClass_cons(pobj,MY_CLASS_CHARP_INT,"test2",1);
MyClass_Print(pobj);
MyClass_dest(pobj);
free(pobj);
Для более компактного представления такого подхода можно соорудить вот такой вспомогательный инклуд:

Code: Select all

// file shaclass.h
					
#ifndef CLASS
   
#define CON(x,y) x##y
#define NEW(x) CON(new_,x)
#define DEL(x) CON(del_,x)
#define CONS(x) CON(x,_cons)
#define CONS_(x) CON(x,_cons_)
#define DEST(x) CON(x,_dest)
#define CLASS_BEGIN(x) typedef struct _##x {
#define CLASS_END(x) } x;
#define PUBLIC extern
#define METHOD(x,y) CON(x,_##y)
#define BEGIN(x) CLASS_BEGIN(x)
#define END(x) CLASS_END(x) \
 PUBLIC void CONS(CLASS) (CLASS *this, int t, ...); \
 PUBLIC void CONS_(CLASS) (CLASS* this, int t, va_list a); \
 PUBLIC void DEST(CLASS) (CLASS *this); \
 PUBLIC CLASS* NEW(CLASS) (int t, ...); \
 PUBLIC void DEL(CLASS) (CLASS *this); 

#else

void CONS(CLASS) (int t, ...)
{
    va_list a;
    va_start(a,t);
    CONS_(CLASS) (p,t,a);
    va_end(a);
}
					   
CLASS* NEW(CLASS) (int t, ...)
{
    CLASS* p;
    va_list a;
    va_start(a,t);
    p = (CLASS*)malloc(sizeof(CLASS));
    if(p!=NULL)
       CONS_(CLASS) (p,t,a);
    va_end(a);
    return p;
}
			
void DEL(CLASS) (CLASS* p)
{
    DEST(CLASS) (p);
    free(p);
}

#endif
И пример кода:

Code: Select all

#include "shaclass.h"

#define CLASS MyClass

BEGIN(CLASS)
 int id;
 char str[10];
END(CLASS)

PUBLIC void METHOD(CLASS,Print) (CLASS *this);

#include "shaclass.h" // bodies

#define MY_CLASS_VOID 0
#define MY_CLASS_CHARP 1
#define MY_CLASS_CHARP_INT 2

void MyClass_cons_(MyClass* this, int t, va_list a)
{
 if(t>=MY_CLASS_VOID)
 {
    *this->str = 0;
    this->id = 0;
 }
 if(t>=MY_CLASS_CHARP)
 {    
    strncpy(this->str,va_arg(a,char*),10);
    this->str[9] = 0;
 }
 if(t>=MY_CLASS_CHARP_INT)
 {    
    this->id = va_arg(a,int);
 }
}

void MyClass_dest(MyClass* this)
{
}

void MyClass_Print(MyClass* this)
{
 printf("id=%i str='%s'\n",this->id,this->str);
} 

main()
{

MyClass obj,*pobj;

MyClass_cons(&obj,MY_CLASS_CHARP,"test");
MyClass_Print(&obj);
MyClass_dest(&obj); 

pobj2 = new_MyClass(MY_CLASS_CHARP_INT,"test2",2);
MyClass_Print(pobj2);
del_MyClass(pobj2);

}	
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

К наследованию подойдем с другой стороны:

Code: Select all

class A
{
 int i,j;
public:
 A(int a){i=j=a;}
 int a(){return i+j;}
};

class B : public A
{
 int k;
public:
 B(int a):A(a){k=a;}
 int b(){return k;}
};
На голом си можно сделать вот что:

Code: Select all

#include "shaclass.h"

#define CLASS A

#define CLASS_A \
 int i; \
 int j; 

BEGIN(CLASS)
CLASS_A
END(CLASS)

PUBLIC int METHOD(A,a) (CLASS this);

#include "shaclass.h"

void A_cons_(A* this, int t, va_list a)
{
 this->i = this->j = t;
}

void A_dest(A* this)
{
}

int A_a(A* this)
{
 return this->i + this->j;
}

#undef CLASS
#define CLASS B

#define CLASS_B \
 CLASS_A \
 int k; 

BEGIN(B)
CLASS_B
END(B)

PUBLIC int METHOD(B,a) (CLASS this);
PUBLIC int METHOD(B,b) (CLASS this);

#include "shaclass.h"

void B_cons_(B* this, int t, va_list a)
{
 A_cons_((A*)this,t,a);
 this->k = t;
}

void B_dest(B* this)
{
 A_dist((A*)this);
}

int B_a(B* this)
{
 return A_a((A*)this);
}

int B_b(B* this)
{
 return this->k;
}

Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
CHRV
God
Posts: 1101
Joined: 29 Dec 2003 01:00
Location: Москва

Re: Объектно-ориентированное программирование на Си

Post by CHRV »

Shaos wrote:но что делать с непростыми стилями? Начнём с простого - имеем вот такой код на C++:
Для темплайтов мы написали свою распарсилку котроая умеет разворачивать в код (что по сути и делается компилятором), так как у нас один компилер для 68К не умеет работать с темплайтами.
Большая проблема - это множественное наследование (ну если учесть что это зло, то можно требовать не использовать)...
Московский филиал NedoPC http://www.nedopc.com
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Объектно-ориентированное программирование на Си

Post by Shaos »

CHRV wrote:
Shaos wrote:но что делать с непростыми стилями? Начнём с простого - имеем вот такой код на C++:
Для темплайтов мы написали свою распарсилку котроая умеет разворачивать в код (что по сути и делается компилятором), так как у нас один компилер для 68К не умеет работать с темплайтами.
А что GCC для m68k уже отменили?
CHRV wrote: Большая проблема - это множественное наследование (ну если учесть что это зло, то можно требовать не использовать)...
Ну на чистом Си множественное наследование вполне себе возможно - единственное ограничение что нельзя использовать теже самые имена для членов классов в наследуемых "классах".
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
CHRV
God
Posts: 1101
Joined: 29 Dec 2003 01:00
Location: Москва

Re: Объектно-ориентированное программирование на Си

Post by CHRV »

Shaos wrote:А что GCC для m68k уже отменили?
Gcc строит крайне неоптимальный код, во вторых под него нет отладчика, в третьих девайс оптимизирован под SDS.
Московский филиал NedoPC http://www.nedopc.com
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Объектно-ориентированное программирование на Си

Post by Shaos »

CHRV wrote:
Shaos wrote:А что GCC для m68k уже отменили?
Gcc строит крайне неоптимальный код, во вторых под него нет отладчика, в третьих девайс оптимизирован под SDS.
Неправильный вы GCC смотрели. Для x86 и Sparc строит более чем оптимальный код (опцию -O2 не забыли включить? ;-)
А в качестве отладчика GDB для GCC всю жизнь выступал...
Что такое SDS?
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
DawnON.com
Novelist
Posts: 30
Joined: 17 May 2008 15:26
Location: 79.124.149.121

Post by DawnON.com »

Во времена, когда Модула соперничала с Трубо-Паскалем, а C с C++ и с Паскалем,
а не изысканные вина не хватало денег (тем более у меня, мне даже анкету участника Gree Card Lottery фирма посредник заполнила так дёшево чтобы потом выбросить). Так чтобы восполнить недостаток в напитках исполненных тонкого аромата и самое главное пьянящих, приходилось смешивать отдельно пьянящее и отдельно ароматное. И походило это на смешивание объектно-ориентированного программирования с языком C в некоторых трансляторах (компиляторах) и стандартах формальных грамматик (языках и версиях языков). Но были такие кто потреблял продукт необычно- т.е. не смешивая и назывался такой продукт "чистяк".

Вот Вам объектно-ориентированное программирование на чистом C.

Code: Select all

#define Class1 class1 *

struct class1
{
int some, other;
};

Class1 class1_new()
{
Class1 this;
this=(void *)malloc(sizeof(struct class1));
this->some=0;
this->other=0;
return(this);
};

void class1_delete(Class1 this)
{
free (this);
};

void class1_some(Class1 this, int val)
{
this->some=val;
}

void class1_other(Class1 this, int val)
{
this->other=val;
};

int class1_together(Class1 this)
{
return(this-some+this->other);
};

/*Class Dawn from DawnON.com*/

#define Dawn dawn *
struct dawn
{
int lighting;
};

Dawn DawnON()
{
Dawn this;
this=malloc(sizeof(struct dawn));
this->lightning=0;
return(this);
};

void DawnOFF(Dawn this)
{
free(this);
}

void DawnLightning(Dawn this)
{
this->lightning=1;
};

int DawnStatus(Dawn this)
{
return(this->lightning);
};

/* class Dawn is perfected */

int main(int so_many, char * such_arguments)
{
Class1 ex1, ex2;

Dawn on_monday, on_tuerday;

ex1=class1_new();
ex2=class1_new();

class1_some(ex1,5);
class1_other(ex1,7);

class1_some(ex2,class_together(ex1));
class1_other(ex2,2);

printf("ex2->together=%d\n",class1_together(ex2));

class1_delete(ex1);
class1_delete(ex2);

on_monday=DawnON();
DawnLightning(on_monday);
if  (DawnStatus(on_monday))
    {
    printf("If is a dawn on monday\n");
    }
DawnOFF(on_monday);

on_thuerday=DawnON();
if (!DawnStatus(on_thuersday))
    {
    printf ("A dawn not yet came on thuerday");
    }
DawnLightning(on_thuerday);
DawnOFF(on_thuersday);
/* Monday 19 of May 2008 11:53 p.m. */
}

Приблизительно к такому виду компилятор внутри преобразовывает программу когда транслирует её с C++ в более удобные для генерации кода абстракции.
Много других свойств C++ на прямую не связаны с Объектно Ориентированным
Программированием и по немножку появляются в новых спецификациях C.
Но по большему счету C уже устарел многие его свойства делают его менее привлекательным даже по сравнению с PL/2 (его конкурентом на этапе утверждения как языка программирования общего назначения).
Last edited by DawnON.com on 20 May 2008 11:44, edited 2 times in total.
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

DawnON.com wrote:Приблизительно к такому виду компилятор внутри преобразовывает программу когда транслирует её с C++ в более удобные для генерации кода абстракции...
Это уже давно не так :no:
Программирование на C++ сегодня - это в первую очередь темплейтное метапрограммирование...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
DawnON.com
Novelist
Posts: 30
Joined: 17 May 2008 15:26
Location: 79.124.149.121

Post by DawnON.com »

Shaos wrote:
DawnON.com wrote:Приблизительно к такому виду компилятор внутри преобразовывает программу когда транслирует её с C++ в более удобные для генерации кода абстракции...
Это уже давно не так :no:
Программирование на C++ сегодня - это в первую очередь темплейтное метапрограммирование...
Вообще-то я говорил от трансляторе с этого языка, а не о стиле программирования.
(Как работает программа транслятор (компилятор), а не как работает программист).

Под генерацией кода подразумевается некое автоматизирование действие выполняемое посредством некого аппаратного устройства, или программно аппаратного комплекса, результатом которого есть некоторый машинный код или некоторые данные в некотором формате содержащие машинный код.
А не как не процесс создания исходного кода программы программистом (автором такого кода).

Касательно вашего определения как темплейтного метапрограммирования, если это программирование с использованием неких штампов/клише/темплейтов посредством некого объединение по неким мета-принципам то:
  1. Такое программирование может быть применено и к объектно ориентированному, и не к объектно ориентированному.
  2. и исходит скорее из свойств языка C++ описанных в некоторых параметрах, напрямую не относящихся к объектно ориентированному.
  3. Смею предположить что мета программирование - больше предрасположено проявляться в так называемом функциональном программировании, до которого практически весь код на C++ увиденный мною в исходных кодах аж никак не относиться.
Мало того полезная идея объектно ориентированного программирования и изящной лексики в стиле языка C практически сходят не нет в современных мегабайтах кода, который непонятно что делает.

Лично я работаю над новым языком программирования, в котором осталось не так много места для творчества как некоторых неявно представленных запросов индустрии. По крайней мере уже несколько раз концепция такого языка кардинально улучшилась после различного рода дискусий (обсуждений), на тему языков программирования. Но не все сразу.
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

Задумался я о том, можно ли на голом Си покрыть всё разнообразие возможностей объектно-ориентированного программирования, которое даёт Си++.
А есть какие-либо более-менее стандартные приёмы, когда алгоритм,
реализованный на С++ желательно откатить на С?
Сталкивался с этим довольно часто, поскольку в качестве С/С++ юзаю
Борланд Билдер. На нём некоторые конструкции - в упор не идут...
Что-то у меня получается порой переделать довольно легко, а что-то
в упор не откатывается.
Совет - выкинь ты свой Билдер - неприемлем. Я на нём всёж довольно
много работал, привык...
User avatar
Shaos
Admin
Posts: 24086
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

сильно зависит от того насколько изысканные изыски сиплюсов заюзаны в алгоритме - если эзотерика последних лет, то вряд ли...
Я тут за главного - если что шлите мыло на me собака shaos точка net
d_wanderer
Senior
Posts: 180
Joined: 28 Feb 2006 21:34

Post by d_wanderer »

Shaos wrote:Засылай
Саш, тут Linus Torvalds написал об использовании C++ в весьма колоритных выражениях типа bullshit и тому подобному... Ссылочку сходу не приведу, но написано было смачно...
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

d_wanderer wrote:Linus Torvalds написал об использовании C++ в весьма колоритных выражениях типа bullshit и тому подобному... Ссылочку сходу не приведу, но написано было смачно...
Это наверно отголоски какой-то холливор... Не люблю когда ругают языки программирования.
Они всёж сделаны людьми и для людей.
Другое дело, что в большинстве они имеют некую направленность, но в принципе
на всём можно написать всё.
А всёж интересно было бы ссылочку глянуть. Читал я, что Linus Torvalds
высказался в том плане, что человек он обеспеченный и ему на многое плевать...
А тут...
User avatar
Lavr
Supreme God
Posts: 16689
Joined: 21 Oct 2009 08:08
Location: Россия

Post by Lavr »

Не это ли??? (Нарыл по Гуглю: Linus Torvalds C++ bullshit)
Linus Torvalds on C++ wrote:*YOU* are full of bullshit.

C++ is a horrible language. It's made more horrible by the fact that a lot
of substandard programmers use it, to the point where it's much much
easier to generate total and utter crap with it. Quite frankly, even if
the choice of C were to do *nothing* but keep the C++ programmers out,
that in itself would be a huge reason to use C.

In other words: the choice of C is the only sane choice. I know Miles
Bader jokingly said "to piss you off", but it's actually true. I've come
to the conclusion that any programmer that would prefer the project to be
in C++ over C is likely a programmer that I really *would* prefer to piss
off, so that he doesn't come and screw up any project I'm involved with.

C++ leads to really really bad design choices. You invariably start using
the "nice" library features of the language like STL and Boost and other
total and utter crap, that may "help" you program, but causes:

- infinite amounts of pain when they don't work (and anybody who tells me
that STL and especially Boost are stable and portable is just so full
of BS that it's not even funny)

- inefficient abstracted programming models where two years down the road
you notice that some abstraction wasn't very efficient, but now all
your code depends on all the nice object models around it, and you
cannot fix it without rewriting your app.

In other words, the only way to do good, efficient, and system-level and
portable C++ ends up to limit yourself to all the things that are
basically available in C. And limiting your project to C means that people
don't screw that up, and also means that you get a lot of programmers that
do actually understand low-level issues and don't screw things up with any
idiotic "object model" crap.

So I'm sorry, but for something like git, where efficiency was a primary
objective, the "advantages" of C++ is just a huge mistake. The fact that
we also piss off people who cannot see that is just a big additional
advantage.

If you want a VCS that is written in C++, go play with Monotone. Really.
They use a "real database". They use "nice object-oriented libraries".
They use "nice C++ abstractions". And quite frankly, as a result of all
these design decisions that sound so appealing to some CS people, the end
result is a horrible and unmaintainable mess.

But I'm sure you'd like it more than git.

Linus
http://harmful.cat-v.org/software/c++/linus

Довольно давнее сообщение: Date: 2007-09-06 17:50:28 GMT
Кто-бы перевёл... весьма специфичный на разные "термины" текст... :wink: