Read-only property

0

Znacie jakiś trick by zadziałała poniższa konstrukcja?

obj.pPointerToSmth->someMethod();

ale tak, by nie można było zmodyfikować wskaźnika w taki sposób:

obj.pPointerToSmth = someAddress;

Nie chcę zwracać wskaźnika za pomocą metody:

obj.pPointerToSmth()->someMethod();

Oczywiście potrzebuję ten wskaźnik ustawić jeden raz po uruchomieniu programu, po utworzeniu obiektu, na który ma ów wskaźnik wskazywać. Ustawiłbym go sobie jakimś setterem (metodą).

Próbowałem wykorzystać:
http://www.codeproject.com/Articles/118921/C-Properties
ale Visual C++ Express 2010 nie akceptuje kodu properties.h, zwraca:

properties.h(5): error C2143: syntax error : missing ')' before '='
properties.h(5): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
properties.h(5): error C2014: preprocessor command must start as first nonwhite space

Przykład:

// ObjectManager to singleton.
#define objManager ObjectManager::GetInstance()
WinMain()
{
    Window pWindow = new Window(...); // Niech Window będzie jakimś oknem windowsowym.
    objManager.SetPtrToWindow(pWindow);

    // Inny kod...

    objManager.pWindow->Show(); // Wyświetlamy okienko.
    objManager.pWindow = NULL; // Próbujemy zmodyfikować wskaźnik. Źle - kompilator powinien nam w tym miejscu uciąć głowę i rzucić rekinom na pożarcie ;-)
}

EDIT: Udało mi się doprowadzić do działania mechanizm z properties.h, ale ten kawałek kodu:

objManager.pWindow = NULL;

spowoduje wyświetlenie błędu dopiero po uruchomieniu kompilacji. W trakcie edytowania kodu IDE nie podkreśli tego jako błąd - macie pomysł jak rozwiązać również ten problem?

0

Nie znam specyfiki tego co chcesz osiągnąć, bo jesteś bardzo oszczędny ale const jak wspomniałem wystarcza.

using namespace std;

class Foo
{
public:
    Foo( int _zmienna ) : zmienna( _zmienna )
    {}

    const int zmienna;
};

int main()
{
    Foo t( 8 );
    cout << t.zmienna; // jest ok - jest dostep
    t.zmienna = 3; // kompilator sypie error bo zmienna read-only
    return 0;
}

0
class O
{
public:
  void metoda() {}
};
class A
{
private:
  O o;
public:
 O * const wskaznik;
  A(): wskaznik(&o) {}
};
// cos w ten desen. zwroc uwage na const za *
0

Owszem Hostel jest to dobre rozwiązanie i wystarczy, jeśli w założeniu zmiennej będziemy przypisywać wartość tylko jeden raz - w trakcie utworzenia obiektu. Wtedy lista inicjalizacyjna jest "jak znalazł". W sumie na chwilę obecną wystarczy mi to rozwiązanie. Jeśli zajdzie potrzeba modyfikacji zmiennej po utworzeniu obiektu to użyję pewnego tricku, który mi przypomniałeś:

void Foo::SetZmienna(int newVal)
{
	*((int*)(&zmienna)) = newVal;
}
 
int main()
{
    Foo t( 8 );
    cout << t.zmienna;
    t.SetZmienna(9);
    return 0;
}
0

mozna zrobic tez tak:

private: O* o;
public: O*& const const_o;
A(): const_o(o) {}

wtedy o moznesz zmieniac a const_o juz nie

0

W sumie jeszcze jedna rzecz trochę psuje estetykę - jeśli takich zmiennych będzie dużo to konstruktor się rozrośnie o mnóstwo parametrów w liście inicjalizacyjnej.

0

Owszem, tak może być ale trzeba przyznać że dobrą praktyką jest hermetyzacja danych - czyli używanie set() i get(). Publiczne zmienne są często wynikiem złego zaprojektowania. W końcu jeśli zmienna ma być publiczna to można by użyć struktury a nie klasy.

0

proponuje Ci zaczac uzywac C#, tam tego typu rzeczy sa wbudowane w jezyk

0

Owszem, tak może być ale trzeba przyznać że dobrą praktyką jest hermetyzacja danych - czyli używanie set() i get(). Publiczne zmienne są często wynikiem złego zaprojektowania. W końcu jeśli zmienna ma być publiczna to można by użyć struktury a nie klasy.

Tak, wiem. Ale chciałem móc używać konstrukcji:

o.pWnd->someMethod();

zamiast:

o.GetPointerToWnd()->someMethod();

ponieważ mój obiekt to singleton, który będzie używany wewnątrz większości innych obiektów, i taka konstrukcja skraca kod.

proponuje Ci zaczac uzywac C#, tam tego typu rzeczy sa wbudowane w jezyk

Wiem, i chciałbym napisać całość w C#, ale nie mogę bo C# nie obsługuje jednej ważnej funkcji, która jest niezbędna w moim programie, dyskutowałem o tym dzisiaj w tym wątku:
http://4programmers.net/Forum/Newbie/201986-kilka_pytan_odnosnie_c
Jak już tam wspomniałem - na upartego da się to obejść, ale to trochę jak bicie kotka za pomocą młotka. Poza tym jeszcze nie jestem gotów na przepisywanie tego do C# bo nie skończyłem aplikacji, a nie wiem jakie jeszcze napotkam problemy - wciąż muszę wykorzystywać reverse-engineering. Nie chcę mieć potem kolejnego zonka, że czegoś tam się nie da łatwo zrobić w C#.

0

Ja nie widzę tego skrócenia zapisu - zamiast metodę nazwać GetPointerToWnd() możesz w singletonie zrobić zmienną _pWnd oraz metodę zwracającą o nazwie pWnd i wtedy dojdzie Ci tylko nawias.

0

Z tego co się orientuję to kompilator Visual C++ obsługuje właściwości. Jest też dostępna darmowa biblioteka stlsoft (http://www.stlsoft.org) udostępniająca właściwości niezależnie od kompilatora.

1

Sposób implementacji nie powinien być wymuszony fizyczną objętością kodu. Takie podejście jest złe. Liczy się przede wszystkim prostota kodu i niewielka objętość "logiczna". To ile powierzchni ekranu zajmuje kod jest na prawdę sprawą podrzędną (zwłaszcza w czasach wielkich ekranów i mechanizmów uzupełniania składni). Ja rozumiem jakieś makro jeśli coś musi być wielokrotnie powielane etc., ale tak kombinować o jeden nawias? Niedobrze. Wspomniany mechanizm uzupełniania składni sam go będzie wstawiać.

Samemu nieraz próbuję tak bezsensownie kombinować i trzeba się w porę otrząsnąć i postawić do pionu.
Mam nadzieję, że Cię przekonałem. Sam zauważyłeś, że logicznie najlepiej pasuje tu metoda. Więc takiej użyj. Im mniej WTF'owego kodu tym lepiej ;) .

0

Tak, można w C# stworzyć okno o danej nazwie klasy. Jak? CreateWindow().
Całe Windows Forms napisane jest w WinAPI.

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