【问题标题】:final class in c++C ++中的最终类
【发布时间】:2010-11-24 21:14:17
【问题描述】:
class Temp
{
private:
    ~Temp() {}
    friend class Final;
};

class Final : virtual public Temp
{
public:
     void fun()
     {
         cout<<"In base";
     }
};

class Derived : public Final
{
};

void main()
{
    Derived obj;
    obj.fun();
}

上面的代码试图实现不可继承的类(final)。但是使用上面的代码仍然可以创建派生对象,为什么?

只有将 ctor 设为私有时才能实现所需的功能,我的问题是为什么在 dtor 私有的情况下无法实现?

【问题讨论】:

标签: c++ inheritance final virtual-inheritance


【解决方案1】:

C++ FAQ 描述了different ways 来实现这一点——但从你的问题来看,我猜你已经阅读了它们。 ;-)

(另外,main 必须始终返回 int,而不是 void。)

【讨论】:

  • 既然Derived 必须调用Temp 的ctor,它不是也必须调用它的dtor 吗?
  • @sbi:我认为不同的规则适用于析构函数,但您的 Comeau 输出提供了相反的情况。无论如何,我都会保留我的答案,因为它引用了常见问题解答并提到voidmain 上无效。否则,您的答案似乎很到位。看看 VS 编译的代码的行为应该很有趣,特别是如果虚拟基类的析构函数在多重继承层次结构中被多次调用。
  • @Konrad:我也只是猜测,但科莫证实了我的猜测,而不是你的猜测。 :) VC 接受我的代码(我应该在我的回答中写下这个。对不起。)我想这是 VC 中的一个错误。
  • @Konrad:我对此进行了测试,VC++ 可以,虚拟继承可以正常工作。问题仅在于访问权限。 -1 表示“Derived 不需要知道 Temp 的析构函数”。那他为什么要使用虚拟继承呢?
【解决方案2】:

派生类不调用基类的私有析构函数,因此它不需要可见性。

将您的构造函数设为私有,并且仅提供静态生成器函数。

【讨论】:

  • 他知道这样就行了。他问为什么当他也将 dtor 设为私有时它不起作用。
  • 好的 - 更改后查看我的答案。
  • 其实这是一个看起来更有趣的问题。
  • @David:既然派生类调用了ctor,是不是也应该调用dtor?
  • 我不确定构造函数或析构函数是否被调用。我认为 new / delete 可以做到这一点,因此它可能只查看已创建类的可见性。如果你不能创造一些东西,你就不能摧毁它。
【解决方案3】:

好吧,对于这个程序(请提供正确的、可编译的示例)

#include <iostream>

class Temp
{
private:
    ~Temp() {}
    friend class Final;
};

class Final : virtual public Temp
{
public:
    void fun() { std::cout<<"In base"; }
};

class Derived : public Final {};

int main() {
    Derived obj;
    obj.fun();
}

Comeau Online

Comeau C/C++ 4.3.10.1 (Oct  6 2008 11:28:09) for ONLINE_EVALUATION_BETA2
Copyright 1988-2008 Comeau Computing.  All rights reserved.
MODE:strict errors C++ C++0x_extensions

"ComeauTest.c", line 16: error: "Temp::~Temp()" (declared at line 6) is inaccessible
  class Derived : public Final {
                         ^
          detected during implicit generation of "Derived::Derived()" at line
                    21

"ComeauTest.c", line 16: error: "Temp::~Temp()" (declared at line 6) is inaccessible
  class Derived : public Final {
        ^
          detected during implicit generation of "Derived::~Derived()" at line
                    21

2 errors detected in the compilation of "ComeauTest.c".

因为,当有疑问时,我总是相信 como(我只发现过一个错误,但在其他编译器中发现了很多),我认为 VC9(它接受代码)是错误的。 (从那个void main()我想你也使用VC。)

【讨论】:

  • 是的,我用过 VC。谢谢指点,我想我也会试试 gcc。
  • +1 gcc 也抱怨该代码。 VS如何销毁无法访问Temp的Derived,在Final中有什么需要虚拟继承????
  • @frieto:访问保护是一个纯粹的编译器前端特性。它没有魔法。一旦前端接受了代码,后端就会简单地注入一个对 dtor 函数的调用。
  • @frieto:嗯,事实上我我说他们没有考虑虚拟继承来检查 dtor 访问权限。 (不过,他们是为 ctor 做的。)而且事情很复杂,以至于我们中的大多数人猜测而不是知道 VC 是对还是错。
  • @fnieto:我说得对,为什么还要问我? :)(对不起,你的昵称拼错了,顺便说一句。这是一种很难阅读的字体,一旦你和我一样大。)
【解决方案4】:

请注意,在 C++11 中使用 final 关键字存在不可继承的类,如果该类从无继承,则在 : base1, base2, ..., baseN 继承列表或开头的 { 之前指定:

class Final final { };
class Derived : public Final { }; // ERROR

通过一点宏魔法和一些编译器检测工作,可以将其抽象出来以在所有编译器上工作,或者最坏的情况是什么也不做。

【讨论】:

    【解决方案5】:

    奇怪地重复出现的模板模式。使用私有继承。

    template< typename T > class Final
    {
    protected:
        Final() {}
        Final( Final const& ) {}
    };
    
    class X : private virtual Final<X>
    {
      // whatever I want to do
    };
    

    而且你应该发现不可能从 X 派生任何东西,因为虚拟继承意味着派生最多的类必须构造基类,但它无权访问它。

    (我没有测试过这段代码)。

    【讨论】:

      【解决方案6】:

      当然,今天正确的做法是使用final 关键字。例如:

      class Foo final {
      public:
        Foo() {}
        ~Foo() {}
      
        void bar() {
           // ...
        }
      };
      

      【讨论】:

        【解决方案7】:

        我已经修改了发布的原始代码并在g++中验证了这段代码:

        class Temp
        {
        private:
            Temp() {
                cout << "In Temp Class ctor" << endl;
            }
            ~Temp() {}
            friend class Final;
        };
        
        class Final : virtual public Temp
        {
        public:
        
            void fun()
             {
                 cout<<"In base";
             }
        };
        
        class Derived : public Final
        {
        };
        
        int main()
        {
            Derived obj;
            obj.fun();
        
            return 0;
        }
        

        结果: $g++ one.cpp -o one -lm -pthread -lgmpxx -kgmp -lreadline 2>&1

        one.cpp:在构造函数“Derived::Derived()”中: one.cpp:8:9: error: 'Temp::Temp()' is private Temp() {

        one.cpp:25:11: 错误:在此上下文中 类派生:公共最终

        one.cpp:11:9: 错误:'Temp::~Temp()' 是私有的~Temp() {}

        one.cpp:25:11: 错误:在此上下文中 类派生:公共最终

        one.cpp:11:9: 错误:'Temp::~Temp()' 是私有的 ~Temp() {}

        注意:最好不要将 void 与 'main' 一起使用。

        谢谢,

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多