【问题标题】:Why don't protected C++-Cli destructors cause compilation errors?为什么受保护的 C++-Cli 析构函数不会导致编译错误?
【发布时间】:2015-04-30 16:40:55
【问题描述】:

如果我编译并运行以下内容:

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;
}

...代码编译没有错误并运行给我这个:

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 destructor


    【解决方案1】:

    这是一个泄漏抽象问题。 C++/CLI 有几个,我们已经解决了 const 关键字问题。在这里大致相同,运行时没有任何析构函数的概念,只有终结器是真实的。所以必须造假。创造这种错觉非常重要,原生 C++ 中的 RAII 模式是神圣的。

    它是通过在 IDisposable 接口上附加析构函数的概念来伪造的。使确定性破坏在 .NET 中起作用的一种方法。很常见,例如 C# 语言中的 using 关键字调用它。 C++/CLI 中没有这样的关键字,您使用 delete 运算符。就像在本机 C++ 中一样。当您使用堆栈语义时,编译器会自动发出析构函数调用。就像原生 C++ 编译器一样。拯救 RAII。

    体面的抽象,但是是的,它泄漏了。问题是接口方法总是公开的。技术上可以通过显式接口实现使其私有化,尽管这只是权宜之计:

    public ref class Foo : IDisposable {
    protected:
        //~Foo() {}
        virtual void Dispose() = IDisposable::Dispose {}
    };
    

    当你尝试这个时会产生一个非常令人印象深刻的错误列表,编译器会尽可能地反击:)。 C2605 是唯一相关的:“'Dispose':此方法保留在托管类中”。当你这样做时,它无法保持错觉。

    长话短说,IDisposable::Dispose() 方法实现始终是公共的,无论析构函数的可访问性如何。 delete 运算符调用它。没有解决方法。

    【讨论】:

      【解决方案2】:

      除了Hans详细回答C++/CLI对象上的delete实际上是激活IDisposable接口,接口继承始终是public1,问一下可能有收获

      那么,受保护的析构函数是如何被调用的呢?

      编译器生成的Dispose 方法调用用户定义的析构函数。因为这个Dispose方法是类的成员,所以它可以访问protectedprivate类的成员,比如析构函数。

      (在本机 C++ 中,编译器不受可访问性规则的约束,因为它是强制它们的那个。在 .NET 中,IL 验证器强制它们。)


      1 实际上,他的解释集中在编译器不允许显式实现IDisposable::Dispose(),在这种情况下它可能是私有成员。但这完全无关紧要。 virtual 成员可以通过声明类型访问。而delete 不调用object-&gt;Dispose(),它调用safe_cast&lt;IDisposable^&gt;(object)-&gt;Dispose()

      【讨论】:

        猜你喜欢
        • 2011-06-09
        • 1970-01-01
        • 2017-10-30
        • 1970-01-01
        • 2011-01-24
        • 2012-09-27
        • 1970-01-01
        • 2020-03-06
        • 2016-05-13
        相关资源
        最近更新 更多