Why and when to pass class types in C++ by pointer?
Consider the following code:
class Abstract{
public:
virtual void printStuff()=0;
};
class Derived: public Abstract{
public:
void printStuff(){
printf("Stuffn");
}
};
Now, let's say I want to create a function that uses the printStuff method from Abstract class. Before I learned that only one way is possible in C++, I thought that there would be two ways: the less obvious with pointers, and the more obvious, similar to what you would 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 one is forbidden in C++. However, I don't really understand the underlying reason for such design. Don't the above functions look identical, aside from the pointer vs. actal object being passed as an argument?
As a follow-up question: what is the preferred way to build classes that have to "contain" other, abstract, classes as one of the fields? If the answer to this question is also: "pointers", then am I missing something, or do I have to keep track of those objects' timelife myself (ie deleting them manually)? For non-abstract classes this is not an issue, as if I don't use pointers, then whenever that object gets out of scope, it gets automatically deleted (destructors called and so on). But if I have to use pointers, it looks like that micro-management takes a lot of unnecessary time and code.
Is there any better way to approach this?
You can't pass an abstract class by value because it can't be instantiated. In most cases pass-by-value is the wrong thing to do anyway (or at least the non-optimal). What you're looking for is pass by reference:
void ref_function(Abstract & abs)
{
abs.printStuff();
}
When you pass by reference any modifications made to abs
inside ref_function
are applied to the same instance that exists outside of the function. Ideally in your test case, you'd want to pass the object as const Abstract & abs
which will prevent any changes from being made to the object. In your example though, you would need to mark printStuff
as const to denote that it will not change the object it's invoked on - the signature would change to virtual void printStuff() const
In response to your other question about how ownership of abstract classes should work.. remember that you can't actually have an instance of an abstract class, so what you're talking about is holding a pointer to some derived object via a handle to its abstract base class. You probably want to use std::unique_ptr for this as it will properly delete the owned 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>())
{
}
There are actually five different possibilities to pass 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);
Because it is not visible from the call of passByReference(o)
that the call may modify 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 abhor the use of pointers because they don't play well with smart pointers like std::unique_ptr<>
and std::shared_ptr<>
. If you manage your objects with these smart pointers, you must always pass the smart pointer instead of a naked pointer/reference, usually by const-reference:
void passBySmartPointer(const std::shared_ptr<Abstract>& o);
void passConstBySmartPointer(const std::shared_ptr<const Abstract>& o);
With this approach, you never see a naked pointer in your code...
(The reason for the need to pass the smart pointer is that the chain of smart pointers must not be broken: If you convert a smart pointer to a naked pointer, and then back to a smart pointer, the second smart pointer does not know about the first, and you'll get trouble. There are other means to avoid this, but this is way beyond the scope of this answer.)
链接地址: http://www.djcxy.com/p/20732.html上一篇: 指针大小和通行证