基类中的重载方法,默认使用成员变量

时间:2016-06-13 13:33:18

标签: c++ overloading method-overriding

我有一个Class结构如下:

class Base {
    public:
        void setDefault( uint8_t my_default ) { m_default = my_default; }

        void method( uint8_t * subject ) { method( subject, m_default ); }
        virtual void method( uint8_t * subject, uint8_t parameter ) =0;

    protected:
        uint8_t m_default;
};

class Derived1 : public Base {
    public:
        void method ( uint8_t * subject, uint8_t parameter ) { /* do something to subject */ }
};

class Derived2 : public Base {
    public:  
        void method ( uint8_t * subject, uint8_t parameter ) { /* do something different to subject */ }
};

我希望能够在method( ... )派生的类的任何实例上调用Base,它将使用成员变量作为默认参数调用派生类中定义的方法。

从我在Stack Overflow here上的其他地方读到的内容,覆盖必须具有相同的签名,这就是它不能编译的原因。

这种方法是否有任何潜在的含糊之处?

我可以通过两种方式来解决这个问题:

  1. 为每个派生类声明默认method( void ),但这似乎不是很干
  2. 为默认方法使用不同的名称(例如defaultMethod( uint8_t * subject )),但我觉得这会让我的课程不那么直观
  3. 有更好的解决方法吗?

    这是一个完整的例子,它不会编译(Arduino IDE 1.7.9):

    class Base {
        public:
            void setDefault( uint8_t my_default ) { m_default = my_default; }
    
            void method( uint8_t * subject ) { method( subject, m_default ); }
            virtual void method( uint8_t * subject, uint8_t parameter ) =0;
    
        protected:
            uint8_t m_default;
    };
    
    class Derived1 : public Base {
        public:
          void method ( uint8_t * subject, uint8_t parameter ) { *subject += parameter; }
    };
    
    class Derived2 : public Base {
        public:  
          void method ( uint8_t * subject, uint8_t parameter ) { *subject *= parameter; }
    };
    
    Derived1 derived1;
    Derived2 derived2;
    
    uint8_t subject = 0;
    
    void setup() {
      // put your setup code here, to run once:
      derived1.setDefault( 3 );
      derived2.setDefault( 5 );
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      derived1.method( &subject, 1 );  // subject == 1  
      derived2.method( &subject, 2 );  // subject == 2  
    
      // won't compile with this line:
      derived1.method( &subject );  // subject == 5
    }
    

    产生的错误是:

    over-ride-load.ino: In function 'void loop()':
    over-ride-load.ino:39:29: error: no matching function for call to 'Derived1::method(uint8_t*)'
    over-ride-load.ino:39:29: note: candidate is:
    over-ride-load.ino:14:12: note: virtual void Derived1::method(uint8_t*, uint8_t)
    over-ride-load.ino:14:12: note:   candidate expects 2 arguments, 1 provided
    Error compiling.
    

2 个答案:

答案 0 :(得分:3)

我相信您正在寻找的是using指令。

您已在Base中正确完成了所有操作。虽然使用默认参数(通常)比定义第二个函数更好,但是根据您的要求(使用成员),这里不可能:所以你定义了第二个重载函数来修复它(并定义它inline - kudos !)。

但问题来自派生类。如果你没有覆盖虚函数,一切都会好的:method的两个版本都可供你使用。但是您必须覆盖它,因此您可以使用method(subject);有效地“屏蔽”method(subject,parameter);的基本版本。

您要做的是将所有Base的{​​{1}}“提升”到各种method中,以赋予它们相同的权重。怎么样?使用Derived指令。

在每个using定义中,输入以下代码:

Derived

将所有using Base::method; 方法“提升”到Base - 同时仍允许您覆盖单个方法。我建议您将该行直接放在每个Derived Derived覆盖的上方。

答案 1 :(得分:2)

  

从我在Stack Overflow上的其他地方读到的内容,覆盖必须具有相同的签名,这就是它不能编译的原因。

它将编译(如果你修复了语法错误)。它将进行编译,因为覆盖具有具有相同的签名:

virtual void method (uint8_t * subject, uint8_t parameter ) =0;

        void method( uint8_t * subject, uint8_t parameter )

另一方面,选项2(支持过载的不同名称)仍然听起来很吸引人。过载有时会很棘手,令人困惑并且反直觉。

但是,即使您的示例是正确的,您可能会发现以下内容不起作用,这可能是违反直觉的:

uint8_t b;
Derived2 d2;
d2.method(&b);

这是因为重载解析的工作原理。你建议的选项2.平凡地解决了这个问题,这就是为什么我建议你这样做。在父级中调用方法的其他方法:

  • 致电d2.Base::method(&b);
  • 仅通过基础对象指针/引用调用单个参数方法。
  • 为每个派生类添加using Base::method;声明。这在John Burger的回答中有更深入的描述。