Why and when to pass class types in C++ by pointer?
考虑以下代码:
1 2 3 4 5 6 7 8 9 10 11 12 | class Abstract{ public: virtual void printStuff()=0; }; class Derived: public Abstract{ public: void printStuff(){ printf("Stuff "); } }; |
现在,假设我想创建一个使用抽象类的printstuff方法的函数。在我了解到C++中只有一种方法是可能的之前,我认为有两种方式:指针越不明显,越明显,类似于你希望用int、字符等做的事情:
1 2 3 4 5 6 7 | void ptr_function(Abstract* abs){ //non-obvious abs->printStuff(); } void non_ptr_function(Abstract abs){ //obvious, analogous to, say, pow(a,b) abs.printStuff(); } |
现在,我明白第二个在C++中是被禁止的。然而,我并不真正理解这种设计的根本原因。除了作为参数传递的指针对象和实际对象之外,上面的函数看起来不一样吗?
作为后续问题:构建必须将其他抽象类作为字段之一"包含"的类的首选方法是什么?如果这个问题的答案也是:"指针",那么我是否遗漏了一些东西,或者我是否必须自己跟踪这些对象的TimeLife(即手动删除它们)?对于非抽象类,这不是一个问题,就像我不使用指针一样,然后每当对象超出范围时,它就会自动删除(调用析构函数等)。但是如果我必须使用指针,看起来微管理需要很多不必要的时间和代码。
有没有更好的方法来解决这个问题?
不能按值传递抽象类,因为它无法实例化。在大多数情况下,传递值无论如何都是错误的(或者至少是非最佳的)。你要找的是通过引用:
1 2 3 4 | void ref_function(Abstract & abs) { abs.printStuff(); } |
当您通过引用传递对
为了回答你关于抽象类的所有权应该如何工作的另一个问题。记住,实际上不能有抽象类的实例,所以您所说的是通过抽象基类的句柄持有指向某个派生对象的指针。您可能希望为此使用std::unique_ptr,因为它将在类被销毁时正确删除所拥有的对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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>()) { } |
实际上,将对象传递给函数有五种不同的可能性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | //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); |
因为从
然而,现在许多C++程序员通常憎恶指针的使用,因为它们不能像EDOCX1、7和EDCX1等8的智能指针玩得好。如果使用这些智能指针管理对象,则必须始终传递智能指针而不是裸指针/引用,通常通过常量引用:
1 2 | void passBySmartPointer(const std::shared_ptr<Abstract>& o); void passConstBySmartPointer(const std::shared_ptr<const Abstract>& o); |
使用这种方法,您永远不会在代码中看到一个裸指针…
(需要传递智能指针的原因是不能破坏智能指针链:如果您将智能指针转换为裸指针,然后再转换回智能指针,则第二个智能指针不知道第一个,您将遇到麻烦。还有其他方法可以避免这种情况,但这远远超出了这个答案的范围。)