代码之家  ›  专栏  ›  技术社区  ›  Thomas Matthews

C++中继承或阻止继承

  •  4
  • Thomas Matthews  · 技术社区  · 13 年前

    我将阻止子类重写基方法,并让子类重写父类中的新方法。换句话说,基类的子类会阻塞基类方法,并将其委托给新方法,其他子类必须重写该方法。我仍然希望基类方法可用。

    下面是一个例子:

    #include <iostream>
    #include <string>
    
    struct Base
    {
        virtual const std::string&  class_name(void) = 0;
    };
    
    struct Level1
        : public Base
    {
    private:  // Prevent child classes from overriding
              //     the Base::class_name method 
        const std::string& class_name(void)
            {
                static std::string name;
                name = "class" + class_name_from_level_1();
                return name;
            }
    protected:
        // This is the "new" or redirected class that child classes
        //    must override.
        virtual const std::string& class_name_from_level_1(void) = 0;
    };
    
    struct Level2
        : public Level1
    {
        static std::string  name;
    
        const std::string&  class_name_from_level_1(void)
            {
                if (name.length() == 0)
                {
                    name = "Level2";
                }
                return name;
            }
    };
    
    
    int main(void)
    {
        Level2  lev2;
        std::cout << lev2.class_name() << "\n";
        return 0;
    }
    

    g++ :

    $ g++ hiding_virt_methods.cpp -o hiding_virt_methods.exe
    hiding_virt_methods.cpp: In function `int main()':
    hiding_virt_methods.cpp:15: error: `virtual const std::string& Level1::class_name()' is private
    hiding_virt_methods.cpp:43: error: within this context
    


    Base::class_name()-->Level1::class_name_from_level_1()-->Level2::class_name_from_level_1()

    全部的 公共方法。

    那么,如何在继承树的不同级别上停止特定基方法的继承链呢?


    我有接口类记录。Id为的类记录从类记录继承并添加Id字段。类记录包含 accept_visitor 接受访客 要应用于ID字段,然后调用虚方法, record_with_id_accept_visitor ,其子代必须实现。

    5 回复  |  直到 13 年前
        1
  •  2
  •   Tony Delroy    13 年前

    对于眼前的问题,您可以将类_name()函数重命名为类_name_impl()或类似的函数,然后在基类中有一个类_name()函数调用实现函数。这样,在对派生对象调用class_name()时,只有基类版本匹配。

    更一般地说,您可以通过在派生类中使用相同的命名函数来阻止调用基类方法的尝试—正如您所做的,但是任何人都可以强制转换为基类并调用他们喜欢的任何函数。不能停止在派生类中重写虚拟方法。。。你只能挫败他们的使用。

    值得记住的是,公共派生类是基类的实例,应该提供基类的接口。

    编辑:重做“现实世界的例子”编辑,你能用一个正常的实现来解释这个问题吗。。。

    #include <iostream>
    
    struct Visitor
    {
        virtual void operator()(int&) const = 0;
    };
    
    struct X
    {
        virtual void visit(Visitor& v) { v(a); v(b); }
        int a;
        int b;
    };
    
    struct X_with_C : X
    {
        int c;
        virtual void visit(Visitor& v) { X::visit(v); v(c); }
    };
    
    struct My_Visitor : Visitor
    {
        void operator()(int& n) const { std::cout << ++n << '\n'; }
    };
    
    int main()
    {
        X x;
        x.a = 10;
        x.b = 20;
        My_Visitor visitor;
        x.visit(visitor);
        X_with_C xc;
        xc.a = -10;
        xc.b = -20;
        xc.c = -30;
        xc.visit(visitor);
        X& rx = xc;
        rx.visit(visitor);
    }
    

    11
    21
    -9
    -19
    -29
    -8
    -18
    -28
    
        2
  •  2
  •   Ion Todirel    12 年前
        3
  •  1
  •   Nemanja Boric    10 年前

    final :

    class Base final {
    

    这也可以应用于虚拟方法:

    class Base{
     protected: 
            virtual void doWork() = 0;
     public:
            virtual void startWork() final { doWork(); }
    
    };
    
    
    class Derived: public Base{
     protected:
            virtual void doWork() override { /* some work */ }
     public:
           //  error: overriding final function ‘virtual void Base::startWork()’
            virtual void startWork() override { /* something else */ } 
    
    
    };
    
        4
  •  0
  •   Eugene Smith    13 年前

        5
  •  0
  •   Cheers and hth. - Alf    13 年前

    看来你是想用一种很难的方式做点什么。

    根据你想要达到的目标,以下可能是一个解决方案。

    #include <iostream>
    #include <string>
    
    struct Base
    {
        virtual std::string class_name() const = 0;
    };
    
    class Level1
        : public Base
    {
    public:
        std::string class_description() const
        {
            return "class " + class_name();
        }
    };
    
    class Level2
        : public Level1
    {
    public:
        virtual std::string class_name() const
        {
           return "Level2";
        }
    };
    
    
    int main()
    {
        Level2  lev2;
        std::cout << lev2.class_description() << "\n";
    }
    

    在上面的代码中,我假设它是用于调试/跟踪之类的。为了身份证的目的调查 typeid (内置的操作员)。