C++ 为什么以及何时在C++;用指针?
考虑以下代码:C++ 为什么以及何时在C++;用指针?,c++,class,oop,pointers,C++,Class,Oop,Pointers,考虑以下代码: class Abstract{ public: virtual void printStuff()=0; }; class Derived: public Abstract{ public: void printStuff(){ printf("Stuff\n"); } }; 现在,假设我想创建一个函数,它使用抽象类中的printStuff方法。在我了解到C++中只有一种方法是可能的之前,我认为有两种方式:指针越不明显,越明显,类似于你
class Abstract{
public:
virtual void printStuff()=0;
};
class Derived: public Abstract{
public:
void printStuff(){
printf("Stuff\n");
}
};
现在,假设我想创建一个函数,它使用抽象类中的printStuff方法。在我了解到C++中只有一种方法是可能的之前,我认为有两种方式:指针越不明显,越明显,类似于你希望用int、字符等做的:
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++中是被禁止的。然而,我并不真正理解这种设计的根本原因。除了作为参数传递的指针和实际对象之外,上述函数看起来是否完全相同
作为后续问题:构建必须“包含”其他抽象类作为字段之一的类的首选方法是什么?如果这个问题的答案也是:“指针”,那么我是否遗漏了什么,或者我是否必须自己跟踪这些对象的时间生命(即手动删除它们)?对于非抽象类,这不是一个问题,就像我不使用指针一样,那么每当对象超出范围时,它就会被自动删除(调用析构函数等等)。但如果我不得不使用指针,那么微观管理似乎需要花费大量不必要的时间和代码
有更好的方法吗?不能按值传递抽象类,因为它无法实例化。在大多数情况下,传递值无论如何都是错误的(或者至少是非最佳的)。您要查找的是通过引用传递:
void ref_function(Abstract & abs)
{
abs.printStuff();
}
void passBySmartPointer(const std::shared_ptr<Abstract>& o);
void passConstBySmartPointer(const std::shared_ptr<const Abstract>& o);
通过引用传递时,对abs
内部ref\u函数
所做的任何修改都将应用于该函数外部存在的同一实例。理想情况下,在测试用例中,您希望将对象作为const Abstract&abs
传递,这将阻止对对象进行任何更改。但在您的示例中,您需要将printStuff
标记为const,以表示它不会更改调用它的对象-签名将更改为virtual void printStuff()const
在回答关于抽象类的所有权应该如何工作的另一个问题时。。请记住,您实际上不可能拥有抽象类的实例,所以您所说的是通过抽象基类的句柄持有指向某个派生对象的指针。您可能希望为此使用std::unique\u ptr,因为当您的类被销毁时,它将正确地删除所拥有的对象
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>())
{
}
类摘要
{
公众:
虚拟void Foo()=0;
};
派生类:公共摘要
{
公众:
虚拟void Foo()重写{}
};
类MyClass
{
公众:
MyClass();
私人:
std::唯一的\u ptr myObject;
};
MyClass::MyClass():myObject(std::make_unique())
{
}
将对象传递给函数实际上有五种不同的可能性:
//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);
因为从调用passByReference(o)
中看不到调用可能修改变量o
,所以我从不使用passByReference。我总是使用passbyconst引用或passbypointer
<>但是,现在很多C++程序员通常厌恶指针的使用,因为它们不能像“代码> STD::UNQuijPPTR <代码>和<代码> STD::SyrdYPPTR 之类的智能指针玩得很好。如果使用这些智能指针管理对象,则必须始终传递智能指针,而不是裸指针/引用,通常通过常量引用:
void ref_function(Abstract & abs)
{
abs.printStuff();
}
void passBySmartPointer(const std::shared_ptr<Abstract>& o);
void passConstBySmartPointer(const std::shared_ptr<const Abstract>& o);
void passbysmart指针(const std::shared_ptr&o);
void passconstbysmart指针(const std::shared_ptr&o);
使用这种方法,您永远不会在代码中看到裸指针
(需要传递智能指针的原因是智能指针链不能断开:如果将智能指针转换为裸指针,然后再转换回智能指针,则第二个智能指针不知道第一个,您将遇到麻烦。有其他方法可以避免此情况,但这远远超出了本文的范围)引用是另一种方式。智能指针是另一种方式。您可以从指针中获得自由,但无需处理生命周期本身的麻烦。请看一下std::unique_ptr和std::Smart_ptr不重复的可能副本:上面的代码对比了按指针传递和按值传递。按引用传递是第三个选项,ignor建议的副本比较1和3,忽略选项2。在本例中,
const
referenceI没有使用const ref,因为printStuff()
不是一个const方法-可能这只是OP的一个疏忽。即使您可以通过值传递非抽象基类,也要意识到您将获得实际对象的切片副本。但是,这里的声明太强烈了。对于具有值行为(如int 和std::complex
。毕竟,每5个值都是5。感谢您的输入。引用看起来真的很有用-在我提到的第一种情况下(函数)。但还有第二个问题,抽象类对象是其他类中的字段。从我刚才对引用属性的简要浏览来看,它们似乎不能不初始化。初始化此类字段的正确方法是什么,以及在哪里(构造函数?)这是最好的地方吗?@ MalSalter关于切片复制问题的好点,这对C++初学者来说可能是一个非常微妙的错误。我觉得最好是夸大新来者的情况,因为这门课更可能坚持下去。你说得对,当然,按价值传递通常是正确的。o用于以这种方式使用的对象。您缺少派生的&&
,因此实际上是六个。但是您不能将示例o
对象传递给该对象。此外,传递常量std::shared_ptr&
;什么是