为什么我不能从 C++ 中该类的实例调用该类的构造函数?
-
23-09-2019 - |
题
类的对象何时可以像常规函数一样调用该类的析构函数?为什么它不能调用同一个类的构造函数作为其常规函数之一?为什么编译器阻止我们这样做?
例如:
class c
{
public:
void add() ;
c();
~c() ;
};
void main()
{
c objC ;
objC.add() ;
objC.~c() ; // this line compiles
objC.c() ; // compilation error
}
解决方案
根据定义,一个构造函数仅创建对象时调用一次。如果你有机会到一个对象,那么它必须已经建立,所以你不能再调用构造函数 - 这就是为什么明确的构造函数调用不准的原因。同样,析构函数只能被调用一次,当对象被销毁。如果这总是可以自动完成的,那么这种语言也将禁止明确析构函数调用。
然而,在某些情况下,你可能想在内存管理的精确控制,并明确创建和内存内销毁对象,您所管理的能力。为此,语言提供了“新布局”,以在任意位置创建一个对象,明确的析构函数调用来销毁对象,这种方式创建。一个明确的构造函数调用不会是有用的,因为你需要能够指定新对象的位置 - 等你拿“放置新的”代替。一个明确的析构函数调用就足够了,所以没有必要去创造某种匹配的“位置删除”。
所以:有显式调用构造函数没有有效的使用,所以他们是不允许的。有显式析构函数调用的有效使用,所以他们(语法)允许,与规则,你必须永远只能使用它们的对象,否则不会被破坏,即对象使用“新位置”创建的,并且在情况叫他们一次。以任何其他方式使用它们,像许多C ++的错误,将编译但给未定义的行为。
其他提示
我觉得你可以显式调用析构函数,如果你确保该实例被替换/与呼叫重新安置到新的:
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
}
我从来没有见过这样的做法,但在逻辑上它应该工作(但C的构造函数可以抛出,在这种情况下,我想,地狱可能在栈展开挣脱)。
不过,你可能想要的是刚分配:
objC = c();
如果析构函数有副作用,你有兴趣,使用复制和交换成语,被调用为“左手”的价值析构函数中执行任务。
必须在类的现有实例上调用析构函数 - 它所做的就是析构该实例。构造函数创建类的全新实例,因此调用现有实例是没有意义的。
这类似于 new 和 delete 的工作方式:
int * p = new int; // call to new needs no existing instance
delete p; // call to delete requires existing instance
请注意,在您的代码中,该对象将被销毁两次,一次是显式销毁,一次是在其封闭范围末尾隐式销毁。通常,只有在执行某些不寻常的操作(可能涉及使用放置 new)时才显式调用析构函数。
如果你真的需要做这样的事情,只需要创建一个额外的功能,从外部从构造本身调用它,但让我们来看看,当你确实需要这样的电话,会发生什么:
#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;
}
一个实例,你可以找到放置新的使用是标准 容器。分配器发生在责任分配 缓冲液(分配构件)和对象构造在该 缓冲液作为它们被添加到容器中。例如,当你做 矢量对象上储备,它保留的空间用于N个对象的含义 对于N分配的空间物体,但不构建它们。然后,当 你的push_back等,来添加元素,它们创造了超过该 缓冲。基本上,它是降低的开销的技术 重复调用内存分配函数。然后完成后,将 矢量析构函数会破坏调用析构函数的对象 明确在它的所有对象,然后调用解除分配() 分配器的功能,以释放内存。希望这有助于。
尝试了这一点:
obj.ClassName ::类名(); //它工作在VC 6.0编译
考虑限制的另一种方式是,一个构造函数的不的只是另一种功能。考虑它的定义:不像其他的功能,它没有返回值,它可能有一个初始化列表。它恰好有一大部分函数的语法是巧合的;它真的只存在初始化对象的新实例的目的。
的构造是有 “C()” 使用新的,即
c objC = new c();
如果你想打电话给你的构造方法的类实例的实际建设之外,那么您可能没有理解构造的目的或正试图把在功能那里,不应该存在。
您是问有关语法的一个特定的风格多语言限制。 C ++可调用一个对象的构造或析构。
c objC;
objC.~c(); // force objC's destructor to run
new(&objC); // force objC's constructor to run
为什么语言设计者不能使用此语法呢?
c objC;
delete(&objC) c; // force objC's destructor to run
new(&objC) c; // force objC's constructor to run
何不:
c objC
objC.~c(); // force objC's destructor to run
objC.c(); // force objC's constructor to run
我的,为什么他们选择他们做了语法意见: 第一种选择是比第二更加灵活。我可以调用构造函数/析构函数上的任何地址不只是一个实例。需要这种灵活性的分配,而不是破坏。另外,在第一选择的删除似乎是非常危险的,一旦虚析构函数中的混乱得到。
可以调用一个实例的类使用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.
}
这不会影响实例objC
的价值,但使用otherObjC
的类构造函数创建一个新实例objC
。
请注意:这可能会做一些你不希望如果静态类型是你有实例的动态类型的基类
谁说你不能?你只需要知道怎么办。
void Foo::Bar() {
*this = Foo(); // Reset *this
}