Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/extjs/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么以及何时在C++;用指针?_C++_Class_Oop_Pointers - Fatal编程技术网

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&
;什么是