C++ instance of same class [closed]

心已入冬 提交于 2020-08-15 18:40:47

问题


I wondered whether it is possible in C++ to do the same stuff like in Java. That means something like this:

public class A {
  private A a1;
  private A a2;
  
  A getA1(){
   return a1;
  }

  A getA2(){
   return a2;
  }

  void setA1(A a1){
   this.a1 = a1;
  }

  void setA2(A a2){
   this.a2 = a2;
  }
}

Now I want the same thing or a workaround in C++.


回答1:


Yes, it's doable in C++. But the syntax would be a little different:

  1. this-> instead of this.

  2. private:/public: instead of private/public per member

  3. remember to have ; at the end of the class

  4. A* as member (or std::uniqe_ptr<A> or std::shared_ptr<A> or std::weak_ptr<A>).


Items 1-3 are merely syntax. Item 4 is an essential difference between Java and C++:

  • In Java an object variable is a reference to the object while in C++ an object variable is a value. This is why you can't hold in C++ a direct member of yourself, as is, the size of the object would be infinite (A holding an actual value of A, holding an actual value of A, ... recursively).

    In Java when A holds an A, it just holds a reference to the other A (yes, you can still access recursively the referenced A, but it is not part of your size, you just hold a reference to it, it is stored elsewhere in memory. The addition to your size is just the size of a reference).

    You can achieve similar semantics in C++ with reference variables or pointers, by adding & for a reference or * for a pointer:

    A& a2 = a1; // a2 is a reference to A, assigned with a reference to a1
                // note that a1 above is assumed to be also of type A&
    
    A* a2 = a1; // a2 is a pointer to A, assigned with the address stored in a1
                // note that a1 above is assumed to be also of type A*
    
  • Java Garbage Collector reclaims unused memory while in C++ the programmer needs to handle that, possibly with C++ tools such as smart pointers.

  • Java Garbage Collector reclaims unused memory via Trace by Reachability, C++ smart pointers are based on scope lifetime. Additionally, C++ shared_ptr is based on reference counting which has its advantages, but is subject to reference cycles possible leak of memory, which should be avoided with proper design of your code.


The C++ version of "holding myself" may look like any of the below (or variations of them), depending on the exact need:

Option 1 - A is holding but not owning a1 and a2

class A {
   A* a1 = nullptr;
   A* a2 = nullptr;

public: 
   A* getA1(){
      return a1;
   }

   A* getA2(){
     return a2;
   }

   void setA1(A* a1){
     this->a1 = a1;
   }

   void setA2(A* a2){
     this->a2 = a2;
   }
};

Option 2 - A is owning a1 and a2 as a unique resource

class A {
   std::unique_ptr<A> a1 = nullptr;
   std::unique_ptr<A> a2 = nullptr;

public: 
   A* getA1(){
      return a1.get();
   }

   A* getA2(){
     return a2.get();
   }

   void setA1(std::unique_ptr<A> a1){
     this->a1 = std::move(a1);
   }

   void setA2(std::unique_ptr<A> a2){
     this->a2 = std::move(a2);
   }
};

Option 3 - A is holding a1 and a2 as a shared resource*

* need to make sure you avoid cyclic ownership leak.

class A {
   std::shared_ptr<A> a1 = nullptr;
   std::shared_ptr<A> a2 = nullptr;

public: 
   auto getA1(){
      return a1;
   }

   auto getA2(){
     return a2;
   }

   void setA1(std::shared_ptr<A> a1){
     this->a1 = a1;
   }

   void setA2(std::shared_ptr<A> a2){
     this->a2 = a2;
   }
};

Option 4 - A is holding weak pointers to a1 and a2*

* the option of std::weak_ptr is relevant in case of possible cyclic dependency, a1 and a2 are owned elsewhere and might not be alive.

class A {
   std::weak_ptr<A> a1 = nullptr;
   std::weak_ptr<A> a2 = nullptr;

public: 
   std::shared_ptr<A> getA1(){
      return a1.lock();
   }

   std::shared_ptr<A> getA2(){
     return a2.lock();
   }

   void setA1(std::shared_ptr<A> a1){
     this->a1 = a1;
   }

   void setA2(std::shared_ptr<A> a2){
     this->a2 = a2;
   }
};

Option 4 code example: http://coliru.stacked-crooked.com/a/92d6004280fdc147


Note that using A& (reference to A) as a member, is not an option, as in C++ reference variables are stronger than Catholic wedding, they're for the lifetime of the variable without any way to reassign to another reference. And they must be assigned to a valid reference when born.

However, if a1 and a2 are known when the object is born, never change and stay alive for the duration of the object's lifetime, then the following option is also possible:

Option 5 - A is holding references to a1 and a2*

* this option is relevant only if the reference to a1 and a2 can be set upon creation, never changes and stays alive for the duration of the object's lifetime.

class A {
   A& a1;
   A& a2;

public:
   A(A& a1, A& a2): a1(a1), a2(a2) {}

   A& getA1(){
      return a1;
   }

   A& getA2(){
      return a2;
   }
};


来源:https://stackoverflow.com/questions/63365537/c-instance-of-same-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!