基class中的重载方法,默认成员变量
Overloading method in base class, with member variable as default
我有一个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 */ }
};
我希望能够在派生自 Base
的 class 的任何实例上调用 method( ... )
,这将调用派生的 class 中定义的方法,使用成员变量作为默认参数。
根据我在 Stack Overflow here 上的其他地方阅读的内容,覆盖必须具有相同的签名,这就是它无法编译的原因。
这种方法是否存在任何潜在的歧义?
我可以想到两种方法来解决这个问题:
- 为每个派生 class 声明默认值
method( void )
,但这似乎不是很干
- 为默认方法使用不同的名称(例如
defaultMethod( uint8_t * subject )
),但我觉得这让我的 class 不那么直观
有没有更好的解决方法?
这是一个完整的例子,它不会编译(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.
From what I've read elsewhere on Stack Overflow here, the override must have the same signature, which is why it won't compile.
它将编译(如果您修复了语法错误)。它将编译,因为覆盖 does 具有相同的签名:
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);
- 仅通过基对象调用单参数方法pointer/reference。
- 向每个派生的 class 添加
using Base::method;
声明。这在 John Burger 的回答中有更深入的描述。
我认为您正在寻找的是 using
指令。
您已在 Base
中正确完成所有操作。虽然使用默认参数(通常)比定义第二个函数更好,但考虑到您的要求(使用成员),这在这里是不可能的:所以您定义了第二个重载函数来修复它(并定义它 inline
- 荣誉!).
但是问题来自派生类。如果您没有重写虚函数,一切都会很好:method
的两个版本都对您可用。但是你必须覆盖它,所以你有效地 "mask" method(subject);
的基本版本与 method(subject,parameter);
.
您要做的是 "promote" 将所有 Base
的 method
放入各个 Derived
中,使它们具有相同的权重。如何?使用 using
指令。
在每个Derived
定义中,放入以下代码:
using Base::method;
将 "promotes" 所有 Base
的方法纳入 Derived
- 同时仍然允许您覆盖个别方法。我建议您将该行直接放在每个 Derived
的 method()
覆盖之上。
我有一个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 */ }
};
我希望能够在派生自 Base
的 class 的任何实例上调用 method( ... )
,这将调用派生的 class 中定义的方法,使用成员变量作为默认参数。
根据我在 Stack Overflow here 上的其他地方阅读的内容,覆盖必须具有相同的签名,这就是它无法编译的原因。
这种方法是否存在任何潜在的歧义?
我可以想到两种方法来解决这个问题:
- 为每个派生 class 声明默认值
method( void )
,但这似乎不是很干 - 为默认方法使用不同的名称(例如
defaultMethod( uint8_t * subject )
),但我觉得这让我的 class 不那么直观
有没有更好的解决方法?
这是一个完整的例子,它不会编译(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.
From what I've read elsewhere on Stack Overflow here, the override must have the same signature, which is why it won't compile.
它将编译(如果您修复了语法错误)。它将编译,因为覆盖 does 具有相同的签名:
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);
- 仅通过基对象调用单参数方法pointer/reference。
- 向每个派生的 class 添加
using Base::method;
声明。这在 John Burger 的回答中有更深入的描述。
我认为您正在寻找的是 using
指令。
您已在 Base
中正确完成所有操作。虽然使用默认参数(通常)比定义第二个函数更好,但考虑到您的要求(使用成员),这在这里是不可能的:所以您定义了第二个重载函数来修复它(并定义它 inline
- 荣誉!).
但是问题来自派生类。如果您没有重写虚函数,一切都会很好:method
的两个版本都对您可用。但是你必须覆盖它,所以你有效地 "mask" method(subject);
的基本版本与 method(subject,parameter);
.
您要做的是 "promote" 将所有 Base
的 method
放入各个 Derived
中,使它们具有相同的权重。如何?使用 using
指令。
在每个Derived
定义中,放入以下代码:
using Base::method;
将 "promotes" 所有 Base
的方法纳入 Derived
- 同时仍然允许您覆盖个别方法。我建议您将该行直接放在每个 Derived
的 method()
覆盖之上。