2017-09-18 105 views
16

Czy dobrze jest używać pola odniesienia const jako programu pobierającego tylko do odczytu w klasach C++?Pole odniesienia const jako własność readonly w klasie C++

Mam na myśli, czy ten kod spełnia dobre praktyki?

class check{ 
private: 
    int _x; 
public: 
    const int& x = _x; 
    void setX(int v){ 
     _x = v; 
    } 
}; 

To działa bardzo podobnie jak właściwości C#, IMHO, i bardzo łatwy i czysty w klasie kodu Zastosowanie:

check s; 
    int i; 
    std::cin >> i; 
    s.setX(i); 
    std::cout << s.x << '\n'; 
    s.setX(7); 
    // s.x = i; // Error 
    std::cout<<s.x<<'\n'; 
+4

I może być const rzucony na zapomnienie :) – StoryTeller

+5

Nie, jest to zła praktyka, ponieważ przechowywanie tego odniesienia może spowodować dodatkowy nadmiar pamięci w porównaniu do prostej funkcji pobierającej inline. Inną sprawą jest to, że nie będzie możliwe wykonywanie sprawdzeń/zapewnień środowiska wykonawczego bez względu na uzyskiwaną wartość. Niestety, nie ma rzeczywistego sposobu naśladowania właściwości C# - podobnie jak w składni. Było [specyficzne dla MS 'rozszerzenie własności '] (https://docs.microsoft.com/en-us/cpp/cpp/property-cpp), ale są one niestandardowe i zostały porzucone. – VTT

+11

Spróbuj przypisać jedno 'sprawdzanie' do innego. – molbdnilo

Odpowiedz

19

zrobić ten kod spotkać dobrych praktyk?

Niezupełnie, ponieważ wprowadza niepotrzebną złożoność i przestrzeń nad głową.

Ponadto nie można wykonywać sprawdzeń i/lub asercji w czasie wykonywania, niezależnie od wartości, do której uzyskiwany jest dostęp.

Co się dzieje z życiem i semantyką?

Spróbuj przypisać jeden kod check do swojego kodu i zobacz, co się stanie. Przydział jest źle sformułowany, ponieważ klasa nie jest możliwa do przypisania. Powinieneś dostarczyć kopię i przenieść konstruktor, aby zająć się referencją, tak aby nie odwoływał się do elementu danych starego obiektu.

Bezpośrednie użycie i bezpośrednia funkcja getera inline.


PS: C#-like properties in native C++?

+0

'Spróbuj przypisanie jednego czeku do drugiego i sprawdzenie, co się stanie. Twój obiekt jest kopiowany "Nie, nie jest. Przydział jest źle sformułowany, ponieważ klasa nie jest możliwa do przypisania. – user2079303

+0

Problem związany z kopiowaniem oznacza tylko, że musisz dostarczyć konstruktory kopiowania i przenoszenia, które zapewniają, że punkty odniesienia zostaną umieszczone w lokalnym obiekcie. Przypisanie nie jest problemem, ponieważ i tak nie można zmienić odwołania w operatorze przypisania, a destruktor również nie jest potrzebny. – cmaster

6

Generalnie to nie dobrą praktyką.

imho, i bardzo łatwy i czysty w klasie kod użytkowania.

Dlaczego powinno to być bardziej przejrzyste i łatwiejsze?

  • Wprowadzasz kolejny element zmienny (bezużyteczny narzut). (Ogólnie rzecz biorąc, odniesienie zostanie zaimplementowane jako dodatkowy wskaźnik dla członka).
  • Uczynia kod trudniejszym w utrzymaniu. W rzeczywistości tworzysz zależności między członami zmiennymi.
  • Powoduje to problemy w zadaniu iw operacjach kopiowania. Jak powinna działać funkcja kopiowania?

Podejście „klasyczny” to dźwięk jaśniejszy przeze mnie, np .:

class Foo { 
public: 
    void set_num(int value) noexcept { m_num = value; } 
    int get_num() const noexcept { return m_num; } 
    void set_string(std::string value) noexcept { 
     m_str = std::move(value); 
    } 
    const std::string& get_string() const noexcept { 
     return m_str; 
    } 
private: 
    int m_num; 
    std::string m_str; 
}; 

Z występy punktu widzenia, powinny być preferowane podejście.

  • Timing złożoność call get_variable na inline funkcji nie wprowadza większe obciążenie niż „podejście odniesienia”. Co więcej, jest wysoce zoptymalizowany przez kompilator (z powodu prostego kodu).
  • Złożoność przestrzeni: nie wprowadza dodatkowego elementu danych.
4

Co proponujesz jest w ogóle zły pomysł:

  • Nie można wdrożyć właściwość wykonując dowolną obróbkę (np getter można przechowywać współrzędne przy użyciu [x, y] a następnie decyduje się na zmianę implementacji, aby użyć [angle, radius] przy zachowaniu tego samego interfejsu publicznego).
  • Używanie zmiennej składowej const wiąże się z narzutem i nie daje żadnej przewagi wydajności w porównaniu z pobierającym w linii.
  • To nie jest idiomatyczne.
  • Gdy opublikujesz swoją klasę i inne osoby zaczną jej używać, utkniesz w niej: jest za późno, aby ją zmienić, aby zamiast niej użyć metody.

Jeśli Twoim zamiarem z właściwościami jest uczynienie kodu bardziej zwięzłym, nie musisz używać słów "get" i "set" w nazwach funkcji; to staroświecka praktyka. Można użyć rzeczywistą nazwą „własności” jako nazwy funkcji, można przeciążać getter i setter:

class Cheque { 
public: 
    int x() const { 
     return x_; 
    } 
    Cheque & x(int newX) { 
     x_ = newX; 
     return *this; 
    } 
private: 
    int x_; 
} 

// Usage: 
// int amt = myCheque.x(1234); 
// Cheque c = Cheque().x(123); 

Skrutacyjną *this jak w powyższym kodzie umożliwia korzystanie method chaining; sposób implementacji idiomu Fluent interface.

1

Gdy C# kompiluje propery, zostaje skompilowany do funkcji pobierającej i ustawiającej.

Oto niektóre kod C#, który dowodzi tego fakt:

using System; 

namespace Reflect 
{ 
    class Program 
    { 
     class X 
     { 
      public int Prop { get; set; } 
     } 

     static void Main(string[] args) 
     { 
      var type = typeof(X); 
      foreach (var method in type.GetMethods()) 
      { 
       Console.WriteLine(method.Name); 
      } 
      Console.ReadKey(); 
     } 
    } 
} 

Twój wyjście powinno być:

get_Prop 
set_Prop 
ToString 
Equals 
GetHashCode 
GetType 

get_Prop to funkcja, która implementuje getter. set_Prop to funkcja implementująca program ustawiający.

Więc nawet jeśli to, co robisz, wygląda podobnie, to wcale nie jest takie samo.

Szczerze mówiąc, prawie wszystko, co można zrobić, aby spróbować naśladować "składnię właściwości" w C++, upada w taki czy inny sposób. Większość rozwiązań kosztuje albo pamięć, albo będzie miała pewne ograniczenia, które sprawiają, że jest bardziej uciążliwa niż użyteczna.

Ucz się żyć z osobami pobierającymi i ustawiającymi. Ustawiacze i setery to dobra praktyka. Są krótkie, są proste, elastyczne, zazwyczaj są dobrymi kandydatami do inline, wszyscy rozumieją, co robią i tak dalej.