【问题标题】:Can you Hide a virtual method in c++?你能在 C++ 中隐藏一个虚方法吗?
【发布时间】:2009-12-01 18:33:37
【问题描述】:

我有一个带有虚函数的基类。

virtual CString& Foo();

我想像这样在子类中重载它

CString Foo();

有没有办法隐藏基类的虚函数?类似于 vb.net 或 C# 中的 new 关键字

【问题讨论】:

    标签: c++ visual-c++


    【解决方案1】:

    为什么有人会做这样的事情?它打破了基类合同。 如果您不想实现与基类具有相同接口的子类,那您为什么要继承呢? 使用组合。

    C++ 中没有与 C# new 关键字等效的关键字。 所以你不能取消方法的“虚拟性”。

    如果您真的想要这样做,您可以随时:

    • 将子类中的方法覆盖为私有。

    • 创建过载。但重载必须有不同的参数

    但是,如果您这样做,恕我直言,您的设计有问题。 我希望每个 C++ 编译器都至少将这两种情况都作为警告捕获。

    【讨论】:

    • 您想要这样做的原因是为了支持向后兼容性。如果基类是由第三方编写的,并且您控制子类,那么如果第三方引入了一个虚拟方法,而该虚拟方法恰好与您的子类上的方法具有相同的名称和签名,那么您的代码将被破坏。更令人费解的是,出于类似的原因,甚至可以创建一个隐藏现有虚拟方法但在 vtable 中占据不同位置的新虚拟方法的用例。
    【解决方案2】:

    首先,坏消息是您不能用另一个仅在返回类型上有所不同的函数覆盖或隐藏虚函数。然后是另一个坏消息,C++ 给了你足够的绳索,让你以许多以前不会考虑的方式吊死自己,并且你可以获得类似的效果:

    struct base {
       virtual std::string const & f() { 
          static std::string s = "virtual"; 
          return s; 
       }
    };
    namespace detail {
       class place_holder; // no need to define it, it is just a place holder (duh)
    }
    struct derived : public base {
       std::string f( place_holder* p = 0 ) { return "crooked"; }
    };
    int main() {
       derived d; std::cout << d.f() << std::endl; // crooked
       base& b = d; std::cout << b.f() << std::endl; // virtual
    }
    

    其中的诀窍在于,通过在派生类中定义具有相同名称和不同参数的方法,您实际上隐藏了基类(除非您在派生类中添加 using base::f,但这样调用就会不明确) .同时,由于唯一添加的参数有一个默认值,您可以不带参数调用它,编译器会为您添加默认参数。

    请注意,您实际上并没有从对象中删除该方法,而是将其隐藏在派生类中。如果方法是通过一个指针或基类的引用来调用的,那么虚方法仍然存在并且会被调用。

    【讨论】:

    • "如果方法是通过指针或基类引用调用的,那么虚方法仍然存在并且会被调用。"这是否意味着,Derived 类的 vtable 也会有指向隐藏函数的指针。
    • 它不起作用。我的意思是,derived::f 不会在第二次调用中被调用。在 gcc 4.8.2 上测试。只是不明白为什么它被赞成。
    【解决方案3】:

    首先你不能覆盖

    virtual CString& Foo()
    

    CString Foo()
    

    因为它们的不同之处仅在于返回类型 - 这不会编译。

    如果有签名的函数

    int foo();
    

    在基类中是virtual - 在派生类中具有相同签名的函数也将是虚拟的;您不必在派生类中指定virtual

    有关虚函数的更多信息(以及更多!),您可以查看C++ FAQ Lite

    【讨论】:

      【解决方案4】:
      1. 您的代码将无法编译。我想你知道,这就是你在这里问这个问题的原因。
      2. 但是,您关心的只是隐藏基类虚函数。为此,请创建另一个具有一些其他参数的函数,而不是基类函数。这将隐藏基类函数。

      【讨论】:

        【解决方案5】:

        从技术上讲,您可以通过在派生类中声明静态方法:

        static CString& Derived::foo()
        

        这听起来很奇怪,但试试吧 - 编译器会吃掉并产生警告。 覆盖将被忽略,virtual Base::foo() 将被隐藏并替换为静态 Derived::foo()

        为什么你需要这样的东西呢?

        【讨论】:

          【解决方案6】:

          不,不是真的。即使你引入一个中间类来创建继承方法private,它也无济于事,因为私有虚方法在 C++ 中仍然是可覆盖的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-09-25
            • 1970-01-01
            • 2011-01-28
            • 2011-05-31
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多