为什么受保护的 C++-Cli 析构函数不会导致编译错误?
Why don't protected C++-Cli destructors cause compilation errors?
如果我编译并运行以下内容:
using namespace System;
ref class C1
{
public:
C1()
{
Console::WriteLine(L"Creating C1");
}
protected:
~C1()
{
Console::WriteLine(L"Destroying C1");
}
};
int main(array<System::String ^> ^args)
{
C1^ c1 = gcnew C1();
delete c1;
return 0;
}
...代码编译没有错误,运行s 给我这个:
Creating C1
Destroying C1
Press any key to continue . . .
如果我在 C++ 中做同样的事情,我会收到如下错误:
1>ProtectedDestructor.cpp(45): error C2248: 'C1::~C1' : cannot access protected member declared in class 'C1'
1> ProtectedDestructor.cpp(35) : compiler has generated 'C1::~C1' here
1> ProtectedDestructor.cpp(23) : see declaration of 'C1'
...那么为什么它在 CLI 中有效?
这是一个抽象漏洞问题。 C++/CLI 有几个,我们已经解决了 const 关键字问题。这里也差不多,运行时没有任何析构函数的概念,只有终结器是真实的。所以必须伪造。创造这种错觉非常重要,原生 C++ 中的 RAII 模式是神圣的。
它是通过将析构函数的概念固定在 IDisposable 接口之上来伪造的。使确定性破坏在 .NET 中起作用的那个。很常见,例如 C# 语言中的 using 关键字调用它。 C++/CLI 中没有这样的关键字,您使用 delete
运算符。就像您在本机 C++ 中一样。当您使用堆栈语义时,编译器会提供帮助,自动发出析构函数调用。就像本机 C++ 编译器一样。营救 RAII。
不错的抽象,但是,是的,它泄漏了。问题是接口方法总是 public。从技术上讲,可以通过显式接口实现使其私有化,尽管这只是权宜之计:
public ref class Foo : IDisposable {
protected:
//~Foo() {}
virtual void Dispose() = IDisposable::Dispose {}
};
当你尝试这个时会产生一个非常令人印象深刻的错误列表,编译器会尽可能地反击 :)。 C2605 是唯一相关的:“'Dispose':此方法在托管 class 中保留”。当你这样做时,它无法保持幻觉。
长话短说,无论析构函数的可访问性如何,IDisposable::Dispose() 方法实现始终是 public。 delete
运算符调用它。没有解决方法。
除了汉斯的详细回答,C++/CLI对象上的delete
实际上是IDisposable
接口的激活,接口继承总是public 1,问一下可能会有收获
How does the protected destructor get called, then?
编译器生成的 Dispose
方法调用用户定义的析构函数。因为这个Dispose
方法是class的成员,它可以访问protected
和private
class成员,比如析构函数。
(在本机 C++ 中,编译器不受可访问性规则的约束,因为它是执行这些规则的人。在 .NET 中,IL 验证程序执行它们。)
1 实际上,他的解释集中在这样一个事实,即编译器不允许显式实现 IDisposable::Dispose()
,在这种情况下它可能是私有成员。但这完全无关紧要。 virtual
成员可以通过声明类型联系到。 delete
不调用 object->Dispose()
,它调用 safe_cast<IDisposable^>(object)->Dispose()
.
如果我编译并运行以下内容:
using namespace System;
ref class C1
{
public:
C1()
{
Console::WriteLine(L"Creating C1");
}
protected:
~C1()
{
Console::WriteLine(L"Destroying C1");
}
};
int main(array<System::String ^> ^args)
{
C1^ c1 = gcnew C1();
delete c1;
return 0;
}
...代码编译没有错误,运行s 给我这个:
Creating C1
Destroying C1
Press any key to continue . . .
如果我在 C++ 中做同样的事情,我会收到如下错误:
1>ProtectedDestructor.cpp(45): error C2248: 'C1::~C1' : cannot access protected member declared in class 'C1'
1> ProtectedDestructor.cpp(35) : compiler has generated 'C1::~C1' here
1> ProtectedDestructor.cpp(23) : see declaration of 'C1'
...那么为什么它在 CLI 中有效?
这是一个抽象漏洞问题。 C++/CLI 有几个,我们已经解决了 const 关键字问题。这里也差不多,运行时没有任何析构函数的概念,只有终结器是真实的。所以必须伪造。创造这种错觉非常重要,原生 C++ 中的 RAII 模式是神圣的。
它是通过将析构函数的概念固定在 IDisposable 接口之上来伪造的。使确定性破坏在 .NET 中起作用的那个。很常见,例如 C# 语言中的 using 关键字调用它。 C++/CLI 中没有这样的关键字,您使用 delete
运算符。就像您在本机 C++ 中一样。当您使用堆栈语义时,编译器会提供帮助,自动发出析构函数调用。就像本机 C++ 编译器一样。营救 RAII。
不错的抽象,但是,是的,它泄漏了。问题是接口方法总是 public。从技术上讲,可以通过显式接口实现使其私有化,尽管这只是权宜之计:
public ref class Foo : IDisposable {
protected:
//~Foo() {}
virtual void Dispose() = IDisposable::Dispose {}
};
当你尝试这个时会产生一个非常令人印象深刻的错误列表,编译器会尽可能地反击 :)。 C2605 是唯一相关的:“'Dispose':此方法在托管 class 中保留”。当你这样做时,它无法保持幻觉。
长话短说,无论析构函数的可访问性如何,IDisposable::Dispose() 方法实现始终是 public。 delete
运算符调用它。没有解决方法。
除了汉斯的详细回答,C++/CLI对象上的delete
实际上是IDisposable
接口的激活,接口继承总是public 1,问一下可能会有收获
How does the protected destructor get called, then?
编译器生成的 Dispose
方法调用用户定义的析构函数。因为这个Dispose
方法是class的成员,它可以访问protected
和private
class成员,比如析构函数。
(在本机 C++ 中,编译器不受可访问性规则的约束,因为它是执行这些规则的人。在 .NET 中,IL 验证程序执行它们。)
1 实际上,他的解释集中在这样一个事实,即编译器不允许显式实现 IDisposable::Dispose()
,在这种情况下它可能是私有成员。但这完全无关紧要。 virtual
成员可以通过声明类型联系到。 delete
不调用 object->Dispose()
,它调用 safe_cast<IDisposable^>(object)->Dispose()
.