c++对象实例化和作用域

C++ object instantiation and scope

本文关键字:作用域 实例化 对象 c++      更新时间:2023-10-16

我是从c#来的(最近),我习惯于像这样实例化对象:

Phone myPhone = new Phone();

直接写

Phone myPhone;

实际上是为类创建了一个holder,但是还没有初始化。

现在我正在用c++写一个小类,我有一个问题。下面是伪代码:

Phone myPhone;
void Initialise()
{
    myPhone = new Phone();
}
void DoStuff()
{
    myPhone.RingaDingDong();
{

实际上这有点误导,因为上面的代码是我想要的,因为我想把我所有的初始化代码放在一个整洁的地方。我的问题是,在c++中,initialize里面的行是不必要的,因为在那之前,一个新的实例已经被第一行创建和初始化了。另一方面,如果我把第一行在initialize()我不能再访问它在DoStuff。它超出了范围,(更不用说在c++中使用"new"和不使用"new"之间的区别了)。如何为类变量创建一个简单的持有人,以便我可以在一个地方初始化它,并在另一个地方访问它?还是说我从根本上就错了?

提前感谢!

如果你的Phone构造函数没有参数,那么你的生活就很简单了——你不需要在Initialize方法中新建这个Phone。它将在创建对象时为您创建,并且将为您管理生命周期。

如果你需要为它获取参数,而它没有Initialize()方法或一些set方法,那么你可能需要使用一个指针(有时可能为空),并让Initialize()调用new并传递这些参数。其他代码需要在使用指针之前检查它是否为空。此外,您还需要管理生命周期(通过编写大3)或使用智能指针,如c++ 11中的shared_ptr。

可以在指针上使用new操作符:

Phone *myPhone;
void Initialise()
{
    myPhone = new Phone();
}
void DoStuff()
{
    myPhone->RingaDingDong();
}

仅在myPhone声明中增加了*,在访问RinaDingDong()时增加了->而不是.。您还必须释放它,因为new正在分配内存:

void destroy()
{
    delete myPhone;
}

注意,如果你这样做,myPhone将是一个指向Phone的指针,而不是一个实际的Phone

我认为你需要在指针上刷一下。你所要做的是可以用指针来实现的。

我的问题是,在c++中,initialize里面的行是不必要的,因为在那之前,一个新的实例已经被第一行创建和初始化了。

这是不正确的。您提供的注释仅对构造函数有效。从您的puesdo代码中,函数initialize是一个全局函数,而不是类的成员函数。

另一方面,如果我把第一行放在initialize()中,我就不能再在DoStuff中访问它了。它超出了范围,(更不用说在c++中使用"new"和不使用"new"之间的区别了)。

请参考有关指针的书籍,您可以使用全局指针并使用new进行初始化。这可以在doStuff

中使用

如果你学过c#,你就知道有两种类型的对象:类和结构。

类被复制、赋值并通过引用传递给函数。所以,他们使用的是参考语义。类也在堆中分配(使用new)。

结构体实现了值复制语义。Struct类型在栈上分配(int、double和其他内置类型都是Struct)。不能以多态方式处理结构体。

在c++中没有这个区别。类和结构本质上是相同的(一部分是默认访问级别)。决定复制语义的不是类的声明,而是类的实例声明。

如果你创建一个指针,其行为与c#中的类非常相似。如果你创建一个对象,其语义将类似于c#中的结构体。

c++也有引用,你应该阅读一下指针和引用的区别

Kate Gregory的回答是正确的,但是我想详细说明一下。c++中一个更强大的思想是,堆栈分配的对象由其包含作用域拥有。例如,如果你想写一个包含电话的类,你只需这样写:

class Secretary { 
    Phone myPhone;
};

现在每次创建秘书时,都会用默认构造函数自动初始化Phone对象。更重要的是,每当Secretary对象被销毁时,其包含的Phone对象也会被销毁。如果你想为Phone使用不同的构造函数,你可以在Secretary的构造函数中使用初始化列表:

class Secretary {
private: // members
    Phone myPhone;
    Phone myCellPhone;
public: // methods
    Secretary() : myPhone("phone constructor", 12, " args") {}
};

在这个例子中,myPhone是用它的3参数构造函数初始化的,myPhone是用它的默认构造函数初始化的。