Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Sposób na uporządkowanie komponentów własnej biblioteki

Ostatnio zmodyfikowano 2014-10-28 09:47
Autor Wiadomość
RazzorFlame
Temat założony przez niniejszego użytkownika
Sposób na uporządkowanie komponentów własnej biblioteki
» 2014-10-27 19:31:00
Otóż pisząc bibliotekę wpadłem na pomysł stworzenia czegoś w stylu menedżera komponentów z mojej biblioteki. Zastanawiałem się co by tu zrobić i zaświeciła mi się lampka. Celem było umożliwienie programiście jak najłatwiejszego tworzenia i dostępu do komponentów. Tutaj przykład:
C/C++
// Test1ComponentRegister.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <iostream>

using namespace std;

// Komponent A

class CompA
{
public:
    int a;
    void draw() { cout << "A: " << a << endl; }
    CompA( int x = 0 ) { a = x; }
};

// Komponent B

class CompB
{
public:
    int a;
    void draw() { cout << "A: " << a << endl; }
    CompB( int x = 1 ) { a = x; }
};

// Komponent C

class CompC
{
public:
    int a;
    void draw() { cout << "A: " << a << endl; }
    CompC( int x = 2 ) { a = x; }
};

// Komponent D

class CompD
{
public:
    int a;
    void draw() { cout << "A: " << a << endl; }
    CompD( int x = 3 ) { a = x; }
};

// Enumeratory komponentów (dla metody get())

enum ECompReg_A { COMPONENT_A };
enum ECompReg_B { COMPONENT_B };
enum ECompReg_C { COMPONENT_C };
enum ECompReg_D { COMPONENT_D };

// Klasa ktora obsluguje wszystkie komponenty

class ComponentRegister
{
    CompA * cA;
    CompB * cB;
    CompC * cC;
    CompD * cD;
public:
    ComponentRegister()
    {
        // Ustawienie poczatkowych wartosci
        cA = NULL;
        cB = NULL;
        cC = NULL;
        cD = NULL;
    }
   
   
    // Tutaj mamy przeladowania funkcji create tak by mozna bylo ta sama funkcja tworzyc rozne komponenty
    void create( CompA * a ) { if( a ) cA = a; }
    void create( CompB * b ) { if( b ) cB = b; }
    void create( CompC * c ) { if( c ) cC = c; }
    void create( CompD * d ) { if( d ) cD = d; }
   
    // Podobnie jak u gory, jednak teraz ta sama funkcja mozna miec dostep do wszystkich komponentow
    CompA * get( ECompReg_A ) { return cA; }
    CompB * get( ECompReg_B ) { return cB; }
    CompC * get( ECompReg_C ) { return cC; }
    CompD * get( ECompReg_D ) { return cD; }
};

int _tmain( int argc, _TCHAR * argv[] )
{
    ComponentRegister myReg;
   
    // Przyklad tworzenia
    myReg.create( new CompA() );
    myReg.create( new CompB() );
    myReg.create( new CompC() );
    myReg.create( new CompD() );
   
    // Przyklad dostepu
    myReg.get( COMPONENT_A )->draw();
    myReg.get( COMPONENT_B )->draw();
    myReg.get( COMPONENT_C )->draw();
    myReg.get( COMPONENT_D )->draw();
   
    system( "pause" );
   
    return 0;
}
Jeszcze innym celem było ominięcie używania szablonów. Jak wiemy używanie szablonów w bibliotekach wymaga udostępnienie kodu (w tym przypadku klasy ComponentRegister). Poza tym, dodatkowym udogodnieniem jest to, że kod jest krótszy. Dla szablonów i tak musielibyśmy definiować funkcje pod określony typ.
Co o tym rozwiązaniu sądzicie?

Edit: A właśnie, jeżeli jakiś użytkownik biblioteki chciałby rozszerzyć klase ComponentRegister to wystarczy stworzyć klase dziedziczącą po ComponentRegister.
P-119529
pekfos
» 2014-10-27 19:43:22
Nie zachwyca. (albo tylko taki przykład..) Czemu nie ma klasy bazowej dla wszystkich komponentów..? Czemu dodawanie nowego typu komponentu wymaga tak wielkich ingerencji? Czemu nie można mieć wielu obiektów jednego typu komponentu? I czemu dostęp do różnych komponentów ma lecieć przez ten 'fajny sposób', zamiast normalnie - po nazwach, które i tak muszą być dostępne. No dobra, jest sobie taki pomysł, ale to wygląda jak dodatkowa warstwa utrudniająca życie.. Podaj praktyczny przykład. I nazwę tematu popraw..

Jak wiemy używanie szablonów w bibliotekach wymaga udostępnienie kodu
Od kiedy?
P-119531
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2014-10-27 19:50:42
Czemu nie można mieć wielu obiektów jednego typu komponentu?
C/C++
enum ECompReg_VecA { COMPONENT_VECTOR_A };

class ComponentRegister
{
    std::vector < CompA *> vCompA;
public:
    ComponentRegister()
    {
    }
   
   
    // Tutaj mamy przeladowania funkcji create tak by mozna bylo ta sama funkcja tworzyc rozne komponenty
    void create( CompA * a ) { if( a ) vCompA.push_back( a ); }
   
   
    // Podobnie jak u gory, jednak teraz ta sama funkcja mozna miec dostep do wszystkich komponentow
    CompA * get( ECompReg_VecA, UINT id = 0 )
    {
        if( vCompA.size() > 0 && id < vCompA.size() )
             return vCompA[ id ];
        else return NULL;
       
    }
};
// ...
int _tmain( int argc, _TCHAR * argv[] )
{
    ComponentRegister myReg;
   
    // Przyklad tworzenia
    myReg.create( new CompA( 1 ) );
    myReg.create( new CompA( 2 ) );
    myReg.create( new CompA( 3 ) );
    // Przyklad dostepu
    myReg.get( COMPONENT_VECTOR_A )->draw();
    myReg.get( COMPONENT_VECTOR_A, 1 )->draw();
    myReg.get( COMPONENT_VECTOR_A, 2 )->draw();
    system( "pause" );
   
    return 0;
}
Pisane bez kompilacji.
Prawdą jest to że trzeba się troche trudzić, ale jeżeli ma to wyglądać schludnie i przyzwoicie to warto. Z resztą jak napisałem - kodu jest nawet mniej niż przy szablonach i nie trzeba męczyć się z plikami .inl, nie trzeba też udostępniać kodu.

Edit:
Jak wiemy używanie szablonów w bibliotekach wymaga udostępnienie kodu
Od kiedy?
Czytałem gdzieś o tym, z resztą sugerowałem się głównie kodem źródłowym SFML gdzie autor właśnie pisze w ten sposób. Jeżeli nie trzeba tego robić to pardon, i prosiłbym o odesłanie do jakiegoś artykułu bo mi też by to ułatwiło prace.
P-119532
pekfos
» 2014-10-27 19:54:56
kodu jest nawet mniej niż przy szablonach i nie trzeba męczyć się z plikami .inl, nie trzeba też udostępniać kodu.
Nie musisz tego dzielić na pliki. Nie chcesz udostępniać kodu..? To nie pisz żadnych bibliotek, przecież trzeba udostępnić definicje klas.. Jak działasz na szablonach, to dojdzie do tego definicja jakichś dwóch, stricte dostępowych metod, na góra kilka linii - a i to nie zawsze.
P-119533
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2014-10-27 20:04:39
Źle zrozumiałeś to co napisałem w pierwszym poście. Nie chodzi mi o to by nie udostępniać całego kodu... Chodzi o udostępnianie kodu definiującego metody lub funkcję.
http://stackoverflow.com​/questions/14238361​/template-method-in-c-static-library
Ja tak czy siak jestem w stanie udostępniać kod zwłaszcza tak małej jego ilości, chodzi jednak o innych ludzi. Przecież gdybym chciał używać tego sam to nie miałbym po co tego tematu zakładać. Głównym powodem jest to, że użytkownikowi łatwiej będzie korzystać z tych wszystkich funkcji. Osobiście nie lubie bibliotek w których by dostać się do jakiegoś komponentu muszę znać ustaloną jego nazwę (wiadomo, trzeba je znać ale chodzi mi raczej o sytuacje gdy komponentów jest pełno i musisz znać dokładną nazwę każdego z osobna).
Przykład:
C/C++
ID3D11Device * getDirectX11Device();
IDXGISharedResource * getDirectXSharedResource();
Można zastąpić z:
C/C++
ID3D11Device * get( EComp_Device );
IDXGISharedResource * get( EComp_SharedResource );
P-119535
pekfos
» 2014-10-27 20:38:31
A enumów nie trzeba tu znać? Dalej jest dokładna nazwa, której trzeba użyć. Dodajesz tylko dodatkową warstwę przerabiającą jedne nazwy na drugie. Taki mechanizm jest po prostu niewygodny. Twórca biblioteki musi pamiętać o jego utrzymywaniu, a w kodzie klienta hmm.. Albo będzie to niewygodne, albo nie będzie klientowi robiło różnicy, czy ten jeden raz pobierze jakąś wartość ręcznie, czy przez taki mechanizm. W najlepszym przypadku nie będzie to gorsze od standardowego podejścia, ale może tylko nie jestem w stanie znaleźć tu teraz istotnych zalet.
P-119539
RazzorFlame
Temat założony przez niniejszego użytkownika
» 2014-10-28 09:47:12
No nie wiem, mi by bylo lepiej używać tego sposobu.
P-119565
« 1 »
  Strona 1 z 1