Dość podstawowe pytanie. Ma do czynienia z preferencjami projektowymi, ale myślę, że są pewne zastrzeżenia, których brakuje.

Chcę mieć instancję niektórych klasy w innej klasie. Sposób, w jaki go widzę, mam 3 opcje:

  1. Masz obiekt class2 wewnątrz class1, jak mam go poniżej. Oznacza to, że zostanie skonstruowany, gdy zostanie skonstruowany instancja class1. Moim problemem jest to, że może wymagać konstruktora domyślnego i / lub kopiowania? Kiedy instancja instancja class1 poniżej, czy konstruuje class2_inst(args) za pomocą tego konstruktora? Lub jest class2_inst już utworzone za pomocą niektórych domyślnych konstruktora i linii class2_inst(args) po prostu kopie anonimowy class2 obiekt?

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
      protected class2 class2_inst;
      public class1(args) : class2_inst(args) {
        ...
      }
    }
    
  2. Mogę mieć wskaźnik do class2:

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
       protected class2* class2_inst;
       public class1(args) {
        class2_inst = new class2(args);
        ...
       }
    }
    

    Ma to przewagę, że Class2 nie jest tworzona instancja, dopóki nie zadzwonię do nowego operatora.

  3. Następnie używa odniesienia zamiast wskaźnika:

    class class2 {
      public class2(args) {
        ...
      }
    }
    
    class class1 {
      protected class2& class2_inst;
      public class1(args) {
        class2_inst = new class2(args);
        ...
      }
    }
    

Chcę class2_inst czas życia, aby dopasować go z class1. Brak śmiesznego biznesu z posiadaniem class2_inst mieszka poza class1. Tak więc odniesienia mogą być drogą.

Z 3 metod, które są preferowanym sposobem i dlaczego?

0
jkang 9 październik 2020, 20:24

1 odpowiedź

Najlepsza odpowiedź

Twoje przykłady są nieco wstecz. Myślę, że zamiast tego miałeś na myśli:

class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2 class2_inst;

  public:
    class1(args) : class2_inst(args) {
      ...
    }
};
class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2* class2_inst;

  public:
    class1(args) {
      class2_inst = new class2(args);
      ...
    }
};
class class2 {
  public:
    class2(args) {
      ...
    }
};

class class1 {
  protected:
    class2& class2_inst;

  public:
    class1(args) {
      class2_inst = new class2(args);
      ...
    }
};

Teraz, że mówi się:

  • Przykład 1 będzie pracować ładnie za to, co chcesz, i jest preferowanym sposobem na przejście: " chcę class2_inst"} Nr życia, aby dopasować to z class1. Brak zabawnego biznesu z posiadaniem {X1}. {X2}} Living Outside of class1. "i odpowiedz na twoje pytanie - Tak, {X4}} odbędzie się bezpośrednio class2_inst, a nie domyślnie skonstruuj go, a następnie skopiuj Anonymous class2 obiekt w nim. Zobacz Konstruktory i listy inicjatora członków.

  • Przykład 2 będzie również działać, ale sprawi, że będzie działać poprawnie , musisz dodać destruktor do class1 do delete Nowy obiekt class2 i Musisz także dodać konstrukcje kopiowania / przenoszenia i kopiowania / przeniesienia operatorów przypisywania do class1, aby skopiować / przesunąć class2 obiektów prawidłowo, na Reguła 3/5/0.

    class class2 {
      public:
        class2(args) {
          ...
        }
    };
    
    class class1 {
      protected:
        class2* class2_inst;
    
      public:
        class1(args) {
          class2_inst = new class2(args);
          ...
        }
    
        class1(const class1 &src) {
          class2_inst = new class2(*(src.class2_inst));
          ...
        }
    
        class1(class1 &&src) {
          class2_inst = src.class2_inst;
          src.class2_inst = nullptr;
          ...
        }
    
        ~class1(args) {
          delete class2_inst;
        }
    
        class1& operator=(const class1 &rhs) {
          if (this != &rhs) {
            class1 tmp(rhs);
            std::swap(class2_inst, tmp.class2_inst);
          }
          return *this;
        }
    
        class1& operator=(class1 &&rhs) {
          class1 tmp(std::move(rhs));
          std::swap(class2_inst, tmp.class2_inst);
          return *this;
        }
    };
    

    Dostajesz całą tę funkcjonalność za darmo w przykładzie 1, ponieważ kompilator automatycznie generuje Ci dodatkowe metody dla Ciebie. Tak, istnieją ważne przypadki, w których bardziej sensowne wykorzystanie wskaźników dla członków, ale ten przykład nie jest jednym z nich.

  • Przykład 3 jest po prostu nieprawidłowy. Nie można przypisać wskaźnika obiektu do odniesienia do obiektu. I dlaczego pomyślałbyś " referencje mogą być sposobem na przejście "? Nie są w tym przypadku.

Tak więc, w skrócie, powinieneś preferować sematyki Wartość , gdy jest to możliwe, ale użyj semantyki wskaźnik / referencyjny w razie potrzeby.

2
Remy Lebeau 9 październik 2020, 17:53