简体   繁体   English

为什么我不能从C ++中该类的实例调用该类的构造函数?

[英]Why can I not call my class's constructor from an instance of that class in C++?

When can an object of a class call the destructor of that class, as if it's a regular function? 类的对象何时可以调用该类的析构函数,就好像它是常规函数一样? Why can't it call the constructor of the same class, as one of its regular functions? 为什么不能将同一个类的构造函数作为其常规函数之一调用呢? Why does the compiler stops us from doing this? 为什么编译器阻止我们这样做?

For example: 例如:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 objC.c() ;  // compilation error
}

I think you can explicitly call the destructor if you make sure that the instance is replaced/recreated with a call to placement new: 我认为,如果您确保实例通过调用placement new替换/重新创建,则可以显式调用析构函数:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

int main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles
 new (&objC) c;  // placement new invokes constructor for the given memory region
}

I've never seen this in practice, but logically it should work (unless c's constructor can throw, in which case, I imagine, hell could break loose during stack unwinding). 我在实践中从未见过,但是从逻辑上讲应该可以工作(除非c的构造函数可以抛出,在这种情况下,我想在堆栈展开时,地狱可能会崩溃)。

However, what you probably want is just assignment: 但是,您可能想要的只是分配:

objC = c();

If the destructor has side-effects that you are interested in, implement assignment using the copy-and-swap idiom which gets the destructor invoked for the "left-hand" value. 如果析构函数具有您感兴趣的副作用,请使用“复制和交换”习惯用法来实现分配,该习俗将为“左侧”值调用析构函数。

By definition, a constructor is only called once, when the object is created. 根据定义,创建对象时,构造函数仅被调用一次。 If you have access to an object, then it must have been created, so you're not allowed to call the constructor again - this is the reason why explicit constructor calls are not allowed. 如果可以访问对象,则必须已创建该对象,因此不允许再次调用构造函数-这就是不允许显式构造函数调用的原因。 Similarly, destructors must only be called once, when the object is destroyed. 同样,销毁对象时,析构函数只能调用一次。 If this could always done automatically, then the language would also forbid explicit destructor calls. 如果这总是可以自动完成,那么该语言还将禁止显式的析构函数调用。

However, in some circumstances, you might want precise control over memory management, and the ability to explicitly create and destroy objects within memory that you are managing. 但是,在某些情况下,您可能希望精确控制内存管理,并希望能够显式创建和销毁要管理的内存中的对象。 For this purpose, the language provides "placement new" to create an object at an arbitrary location, and explicit destructor calls to destroy objects created this way. 为此,该语言提供了“ placement new”以在任意位置创建对象,并且显式析构函数调用将销毁以此方式创建的对象。 An explicit constructor call wouldn't be useful, since you need to be able to specify the location of the new object - so you get "placement new" instead. 显式构造函数调用将无用,因为您需要能够指定新对象的位置-因此,您将获得“ placement new”。 An explicit destructor call is sufficient, so there's no need to invent some sort of matching "placement delete". 显式的析构函数调用就足够了,因此无需发明某种匹配的“放置删除”。

So: there is no valid use for explicit constructor calls, so they are not allowed. 因此:显式构造函数调用没有有效使用,因此不允许使用它们。 There is a valid use for explicit destructor calls, so they are (syntactically) allowed, with the rule that you must only ever use them on objects that won't otherwise be destroyed, ie objects created using "placement new", and in that case call them exactly once. 显式析构函数调用有一个有效用法,因此(在语法上)允许使用它们,其规则是,您只能在不会被破坏的对象(即使用“ placement new”创建的对象)上使用它们,情况下,请致电给他们一次。 Using them in any other way, like so many C++ errors, will compile but give undefined behaviour. 像许多C ++错误一样,以其他任何方式使用它们都可以编译,但行为不确定。

A destructor must be called on an existing instance of a class - destructing the instance is what it does. 必须在类的现有实例上调用析构函数-破坏实例就是它的作用。 A constructor creates a brand new instance of a class, so calling on an existing instance makes no sense. 构造函数会创建一个类的全新实例,因此调用现有实例是没有意义的。

This is similar to the way new and delete work: 这类似于新建和删除工作的方式:

int * p = new int;    // call to new needs no existing instance
delete p;             // call to delete requires existing instance

And note in your code, the object would be destroyed twice, once explicitly, and once implicitly at the end of its enclosing scope. 请注意,在您的代码中,对象将被销毁两次,一​​次被销毁,一次在其封闭范围的末尾隐式销毁。 You typically only explicitly call a destructor if you are doing something unusual, probably involving the use of placement new. 通常,只有在您执行异常操作(可能涉及使用new放置)时,才显式调用析构函数。

If you really need to do something like this, just create an additional function and call it from outside AND from the constructor itself, but let's see what happens when you do need such a call: 如果您确实需要执行以下操作,则只需创建一个附加函数,然后从外部AND调用构造函数本身即可调用它,但是让我们看看当您确实需要这种调用时会发生什么:

#include<new>

class A
{
//members
};

int main()
{
//allocate buffer
char* buffer = new char[sizeof(A)];
//construct A on that memory space
A * ptrToA = ::new (buffer) A();
//destroy the object
ptrToA->~A();
//deallocate the buffer
delete[] buffer;
}

One instance where you can find placement new usage is the standard containers. 您可以找到新用途的展示位置的一个实例是标准容器。 The allocator takes in the responsibility to allocate the buffer (allocate member) and the objects are constructed over that buffer as they are added into the container. 分配器负责分配缓冲区(分配成员),并在将对象添加到容器时在该缓冲区上构造对象。 For example, when you do reserve on vector object, it reserves the space for N objects meaning allocates space for N objects but does not construct them. 例如,当您保留矢量对象时,它将为N个对象保留空间,这意味着为N个对象分配空间,但不构造它们。 Then when you do push_back etc, to add elements, they are created over that buffer. 然后,当您执行push_back等添加元素时,将在该缓冲区上创建它们。 Basically, it is a technique to reduce the overhead of repeated calls to memory allocation function. 基本上,这是一种减少重复调用内存分配函数的开销的技术。 And then when done, the vector destructor would destroy the objects calling the destructor explicitly for all objects in it and then call the deallocate() function of the allocator to release the memory. 然后,完成后,向量析构函数将销毁对象,为其中的所有对象显式调用析构函数,然后调用分配器的deallocate()函数释放内存。 Hope this helps. 希望这可以帮助。

Try this out : 试试看:

obj.ClassName::ClassName() ; obj.ClassName :: ClassName(); // it works in VC 6.0 compiler //在VC 6.0编译器中有效

Another way to think about the restriction is that a constructor is not just another function. 考虑这种限制的另一种方法是,构造函数不仅是另一个函数。 Consider its definition: unlike other functions, it has no return value, and it may have an initializer list. 考虑一下它的定义:与其他函数不同,它没有返回值,并且可能具有初始化列表。 That it just happens to have most of the syntax of a function is kind of a coincidence; 它恰好具有函数的大多数语法,这是一个巧合; it really exists only for the purpose of initializing a new instance of an object. 它的存在仅是为了初始化对象的新实例。

The constructor is there "c()" used with new, ie 构造函数在这里与new一起使用“ c()”,即

c objC = new c();

If you want to call your constructor outside of the actual construction of the class instance then you either haven't understood the purpose of the constructor or are trying to put functionality in there that shouldn't be there. 如果要在类实例的实际构造之外调用构造函数,则可能是您不了解构造函数的用途,或者试图将不应有的功能放在那里。

You are asking about a particular style of syntax more than a language limitation. 您要问的是某种特定的语法样式,而不是语言限制。 C++ allows you to call an object's constructor or destructor. C ++允许您调用对象的构造函数或析构函数。

c objC;
objC.~c();  // force objC's destructor to run
new(&objC); // force objC's constructor to run

Why did the language designers not use this syntax instead? 语言设计者为什么不使用这种语法呢?

c objC;
delete(&objC) c; // force objC's destructor to run
new(&objC) c;    // force objC's constructor to run

Or why not: 或者为什么不这样:

c objC
objC.~c(); // force objC's destructor to run
objC.c();  // force objC's constructor to run

My opinion as to why they chose the syntax they did: The first alternative is more flexible than the second. 我对他们为什么选择自己选择的语法的看法:第一种选择比第二种更加灵活。 I can call the constructor / destructor on any address not just an instance. 我可以在任何地址(不仅是实例)上调用构造函数/析构函数。 That flexibility is needed for allocation, but not for destruction. 分配需要这种灵活性,但销毁则不需要。 Also the first option's delete seems to be very dangerous once virtual destructors get in to the mess. 一旦虚拟析构函数陷入困境,第一个选项的删除似乎也非常危险。

you can invoke the constructor of an instance's class using typeof : 您可以使用typeof调用实例的类的构造函数:

class c
{
public:
   void add() ;
   c();
   ~c() ;
};

void main()
{
 c objC  ;
 objC.add() ;
 objC.~c() ; // this line compiles (but is a bad idea)
 typeof objC otherObjC;  // so does this.
}

This does not affect the value of the instance objC , but creates a new instance otherObjC using objC 's class constructor. 这不会影响实例objC的值,但会使用objC的类构造函数创建一个新实例otherObjC

Note: this may do something you don't expect if the static type is a baseclass of the dynamic type of the instance you have. 注意:如果静态类型是实例的动态类型的基类,那么这可能会做您不希望的事情。

Who says you can't? 谁说你不能? You just have to know how. 您只需要知道如何。

void Foo::Bar() {
  *this = Foo(); // Reset *this
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 构造函数可以在c ++中调用另一个类的构造函数吗? - Can constructor call another class's constructor in c++? 为什么我不能从C ++中的派生类实例调用模板化方法? - Why can't I call a templated method from a derived class instance in C++? C ++如何从具有一个参数的派生类构造函数调用具有两个参数的超类构造函数? - C++ How can I call superclass constructor with two parameters from derived class constructor with one parameter? 我可以将一个类中的函数传递给另一个类的构造函数,并将其存储在那里以便以后调用吗? C ++ - Can i pass a function from a class to a constructor of another class and store it there to call later? C++ c++ - 如何从模板基类的构造函数调用模板超类的构造函数? - How to call a template super class's constructor from a template base class's constructor in c++? 为什么我不能在带有私有构造函数的c ++类中声明一个空的构造函数 - Why can't I declare an empty constructor in a c++ class that extends from one with a private constructor C类中的C ++调用构造函数,来自类C(inherritence) - C++ call constructor in class A from class C (inherritence) 在C ++中,如何在父类的构造函数中测试对象是否是Child类的实例? - In C++, how can I test if an object is an instance of a Child class in the Parent class' constructor? 从C创建C ++类,我可以将C ++对象传递给C中的C ++构造函数吗? - Creating C++ class from C, can I pass C++ objects to C++ constructor in C? C++ 类构造函数可以知道它的实例名称吗? - Can a C++ Class Constructor Know Its Instance Name?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM