Why and when to pass class types in C ++ with a pointer?

Consider the following code:

class Abstract{ public: virtual void printStuff()=0; }; class Derived: public Abstract{ public: void printStuff(){ printf("Stuff\n"); } }; 

Now let's say that I want to create a function that uses the printStuff method from an abstract class. Before I found out that only one way is possible in C ++, I thought there would be two ways: less obvious with pointers and more obvious, similar to what you expect to do with ints, chars, etc .:

 void ptr_function(Abstract* abs){ //non-obvious abs->printStuff(); } void non_ptr_function(Abstract abs){ //obvious, analogous to, say, pow(a,b) abs.printStuff(); } 

Now I understand that the second is forbidden in C ++. However, I do not quite understand the main reason for this design. Don't these functions look the same except for the pointer and the actual object passed as an argument?

As a follow-up question: what is the preferred way to create classes that should โ€œcontainโ€ other abstract classes as one of the fields? If the answer to this question also is: "pointers", then am I missing something, or do I have to track the timelife of these objects myself (i.e. deleting them manually)? For non-abstract classes, this is not a problem, as if I do not use pointers, then whenever this object goes out of scope, it is automatically deleted (called destructors, etc.). But if I need to use pointers, it seems like this microcontrol requires a lot of extra time and code.

Is there a better way to approach this?

+5
source share
2 answers

You cannot pass an abstract class by value because it cannot be created. In most cases, rolling values โ€‹โ€‹are not what you need to do (or at least not optimal). What you are looking for follows the link:

 void ref_function(Abstract & abs) { abs.printStuff(); } 

When passed by reference, any changes made to abs inside the ref_function are applied to the same instance that exists outside the function. Ideally, in the test case, you want to pass the object as const Abstract & abs , which will prevent any changes to the object. In your example, however, you will need to mark printStuff as const to indicate that it will not change the called object - the signature will change to virtual void printStuff() const

In response to your other question about how the property of abstract classes should work ... remember that in fact you cannot have an instance of an abstract class, so what you are talking about contains a pointer to some derived object through a handle its abstract base class. You will probably want to use std :: unique_ptr for this, as it will correctly delete its object when your class is destroyed.

 class Abstract { public: virtual void Foo() = 0; }; class Derived : public Abstract { public: virtual void Foo() override {} }; class MyClass { public: MyClass(); private: std::unique_ptr<Abstract> myObject; }; MyClass::MyClass() : myObject(std::make_unique<Derived>()) { } 
+12
source

In fact, there are five different possibilities for passing an object to a function:

 //Function declarations void passByValue(Derived o); //Not possible with an abstract class. void passByReference(Abstract& o); void passByConstReference(const Abstract& o); void passByPointer(Abstract* o); void passByConstPointer(const Abstract* o); //Function calls Derived o; passByValue(o); passByReference(o); //May change o! passByConstReference(o); passByPointer(&o); //May change o. passByConstPointer(&o); 

Since the call to passByReference(o) does not show that the call can change the variable o , I never use pass-by-reference. I always use either pass-by-const-reference or pass-by-pointer.

However, many C ++ programmers today generally prefer to use pointers because they do not play well with smart pointers such as std::unique_ptr<> and std::shared_ptr<> . If you are managing your objects with these smart pointers, you should always pass a smart pointer instead of an open pointer / link, usually with const-reference:

 void passBySmartPointer(const std::shared_ptr<Abstract>& o); void passConstBySmartPointer(const std::shared_ptr<const Abstract>& o); 

With this approach, you will never see a bare pointer in your code ...

(The reason for passing a smart pointer is because the chain of smart pointers should not be broken: if you convert a smart pointer to a bare pointer and then back to a smart pointer, the second smart pointer does not know about the first, and you will have problems. There are and other ways to avoid this, but this is beyond the scope of this answer.)

0
source

Source: https://habr.com/ru/post/1211026/


All Articles