Elementy OOP w C

0

Potrzebuję przenieść kilka instrukcji z Javy do C. W C jestem początkujący nie znam elementów tego języka oprócz podstawowych typu funkcje, pętle itd.Załóżmy, że mam klasę w Javie o nazwie Car. I tworzę obiekt tej klasy, żeby za jego pomocą odwoływać się do funkcji z tej klasy:

Car car = new Car();
car.drive();

Jak najłatwiej zrobić odpowiednik tego w C ?

Druga sprawa to klasy abstrakcyjne i interfejsy. Mam w Javie jakiś interfejs z metodą getName(), który jest implementowany przez kilka klas. I w innej klasie mam listę/tablicę (mało istotne), w której przechowuję wszystkie klasy implementujące ten interfejs. Następnie w tej klasie wywołuję sobie pętle for i lecę po tej liście wywołując metodę getName() dla każdej klasy implementującej interfejs.

public class CP{
	private final ArrayList<Namer> namers = new ArrayList<>();
	
	public void addNamer(Namer nam) {
		namers.add(nam);
	}

	private void printNames() {
		for (Namer nam: namers) {
			System.out.print(String.format("%-46s", nam.getName()));
		}
		System.out.println("");
	}
}
public class RF implements Namer{
	
	private String name;

	@Override //metoda z interfejsu
	public String getName() {
		return name;
	}
}
public class MainNN {

	public static void main(String[] args) {
		CP cp = new CP();
		RF rf1 = new RF();
		
		cp.addNamer(rf1);
		cp.printNames()	;

	}
}

Jak to osiągnąć w C ? Co w tym języku ma najwięcej wspólnego z klasami abstrakcyjnymi/interfejsami ? Nie potrzebuję tutaj gotowego kodu, wystarczą jakieś hasła pod którymi szukać w Google.

1

OOP w C to nic innego jak struktura z tablicą na wskaźniki na funkcje/metody i zmiennymi jakimiś.

2

nie przenos OOP do C

C to jezyk struktualny ktory pracuje przewaznie na globalnych funkcjach (sa pogrupowane poprzez headery)

5

Jeżeli bardzo chcesz żeby to był OOP, to tu masz książkę: https://www.cs.rit.edu/~ats/books/ooc.pdf

1

Jak dla mnie obsługa plików (FILE*) w C jak najbardziej podpada pod OOP, tylko zamiast syntaxu file.op() jest op(file). Raczej nie zrobisz tak dziedziczenia, ale jakieś prostsze klasy powinno się dać łatwo przenieść.

3
slayer9 napisał(a):
Car car = new Car();
car.drive();

Jak najłatwiej zrobić odpowiednik tego w C ?

Enkapsulacja jest prosta:

// car.h
extern struct Car;
void drive(Car *car);

//car.c
#include "car.h"
typedef struct _car
{
     bool isDriving;
} Car;

void drive(Car *car)
{
    car->isDriving = true;
}

Czyli opaque value/pointer (nie pamiętam dokładnie, nie znam się). Składnia inna, ale zasada ta sama, masz zamknięty stan dostępny przez wybrane funkcje.

slayer9 napisał(a):

Druga sprawa to klasy abstrakcyjne i interfejsy.

Po pierwsze, nie rób tego. Ale jeśli nudzi Ci się wieczorami to najpopularniejsze implementacje dynamicznego polimorfizmu w C opierają się na vtablach, sporo na ten temat znajdziesz w internecie, TUTAJ możesz zacząć.

Jeśli chcesz życiowe przykłady opaque i polimorfizmu w C, to w GTK+ znajdziesz tego sporo, np taki gtkadjustment.h.

1

Kiedyś disassemblowałem kod obiektowy i napisałem prostą implementację klasy, ale nie jest do końca dopracowana, ale powinieneś mniej więcej móc ujrzeć jak to powinno działać.

#include <stdio.h>
#include <stdlib.h>

struct shape {
	int constructor;
	int destructor;
	int vtable;
	int name;
};

struct vtable {
	int print;
};

struct circle {
	struct shape inheritance;
	int radius;
};

void printCricle(int object){
	printf("Jestem obiektem: %s, mam promien: %d\n", (char*)((struct shape*)object)->name, (int)((struct circle*)object)->radius);
}

struct rectangle {
	struct shape inheritance;
	int x;
	int y;
};

void printRect(int object){
	printf("Jestem obiektem: %s, mam x: %d i y: %d\n", (char*)((struct shape*)object)->name, (int)((struct rectangle*)object)->x, (int)((struct rectangle*)object)->y);
}

int destructor(int* object) {
	printf("destructing %s\n", ((struct shape*)object)->name);
	//free((int*)((struct shape*)object)->name);  // name nie jest dynamicznie alokowane
	free((void*)object);
}

int* constructorRect(char* name, int x, int y){
	int size = sizeof(struct rectangle);
	int* ptr = malloc(size);
	((struct shape*)ptr)->destructor = (int)destructor;
	((struct shape*)ptr)->vtable = (int)printRect;
	((struct shape*)ptr)->name = (int)name;
	((struct rectangle*)ptr)->x = x;
	((struct rectangle*)ptr)->y = y;
	return ptr;
}

int* constructorCircle(char* name, int rad){
	int size = sizeof(struct circle);
	int* ptr = malloc(size);
	((struct shape*)ptr)->destructor = (int)destructor;
	((struct shape*)ptr)->vtable = (int)printCricle;
	((struct shape*)ptr)->name = (int)name;
	((struct circle*)ptr)->radius = rad;
	return ptr;
}

int main(void) {
	int* circ = constructorCircle("kolko", 1000);
	int* rect = constructorRect("prostokat", 25, 50);
	
	((void (*)(int*)) ((struct shape*)circ)->vtable)(circ);
	((void (*)(int*)) ((struct shape*)rect)->vtable)(rect);
	
	((void (*)(int*)) ((struct shape*)circ)->destructor)(circ);
	((void (*)(int*)) ((struct shape*)rect)->destructor)(rect);
	
	return 0;
}

3
// Car.h
struct OOVehicle;
typedef struct OOVehicle OOVehicle;;

struct OOCar;
typedef struct OOCar OOCar;

OOCar* OOCarCreate(int numberOfDors);
void OOCarDestroy(OOCar *car);

OOVehicle* OOCarAsVehicle(OOCar *car);

void OOCarDrive(OOCar *car);

// Car_Internal.h
#include "Vehicle_Internal.h"

struct OOCar
{
    struct OOVehicle vehicle;
    int numberOfDors;
};

// Car.c
#include "Car_Internal.h"
#include "Car.h"

…
void OOCarDestroy(OOCar *car)
{
     LocalCarClean(car);
     OOVehicleDestroy((OOVehicle*)car);
}
…
OOVehicle* OOCarAsVehicle(OOCar *car)
{
     return (OOVehicle*)car;
}
…

Da się nawet zrobić polimorfizm, ale jest to strasznie upierdliwe.

1

W C robi się takie OO na pół gwizdka. Robi się struktury i globalne funkcje, które na nich operują (jak wspomnianio). Jeśli chcesz mieć funkcję, która działa na kilku typach, stosujesz unię. Jak to się robi zbyt upierdliwe, a chcesz OO to spróbuj lepiej C++. Wprawdzie można robić wskaźniki do funkcji w strukturach, ale to już się zaczyna mijać z celem. No chyba że masz ważny powód żeby stosowąć OO i nie stosować C++, w co wątpię.

0

Jeszcze dodam, że pierwsze kompilatory C++ generowały kod w C, który był kompilowany do kodu maszynowego.

1 użytkowników online, w tym zalogowanych: 0, gości: 1