重载基类中的方法,默认为成员变量
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
派生的类的任何实例上调用method( ... )
,它将使用成员变量作为默认参数来调用派生类中定义的方法。
根据我在Stack Overflow的其他地方所读到的内容,重写必须具有相同的签名,这就是它无法编译的原因。
这种方法是否存在潜在的歧义?
我可以想出两种方法来解决这个问题:
- 为每个派生类声明一个默认的
method( void )
,但这似乎不是很枯燥 - 为默认方法使用不同的名称(例如
defaultMethod( uint8_t * subject )
),但我觉得这会使我的类不那么直观
有更好的方法吗?
这里有一个完整的例子,它不会编译(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.
我相信您正在寻找的是using
指令。
您在Base
中做的每件事都是正确的。虽然使用默认参数(通常)比定义第二个函数更好,但考虑到您的需求(使用成员),这在这里是不可能的:所以您定义了第二个重载函数来修复它(并将其定义为inline
-kudos!)。
但问题出在派生类上。如果你没有覆盖虚拟函数,一切都会好起来:method
的两个版本都可以使用。但是您必须覆盖它,所以您可以用method(subject,parameter);
有效地"屏蔽"method(subject);
的基本版本。
您要做的是将Base
的所有method
"提升"为各种Derived
,以赋予它们同等的权重。怎样使用using
指令。
在每个Derived
定义中,输入以下代码:
using Base::method;
这将把Base
的所有方法"提升"到Derived
中,同时仍然允许您覆盖单个方法。我建议您将该行直接放在每个Derived
的method()
覆盖之上。
根据我在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;
声明。这在约翰·伯格的回答中有更深入的描述
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 基类中的默认析构函数禁用子类中的移动构造函数(如果有成员)
- C++向量默认为成员参数
- 结构中的默认成员值或默认构造函数参数
- 构造函数可以更改默认成员类型吗?
- 在成员函数外部封闭类的定义中需要默认成员初始值设定项
- 所有版本的 GCC 都与默认成员初始值设定项作斗争,该初始值设定项捕获了这一点,并结合了继承的构造函数
- 如果有默认成员初始化,为什么要使用成员初始化列表
- “在成员函数之外封闭类的定义中需要默认成员初始值设定项” - 我的代码格式不正确
- 使用默认成员初始值设定项对 std::array 的元素进行零初始化
- C - 混合默认成员初始化器和成员初始化列表 - 坏主意
- 为什么默认成员值禁止使用支持列表初始化
- 自定义分配器和默认成员
- C++C-tor处理默认成员值构造异常
- 非静态数据成员上的成员初始值设定项列表和默认成员初始值设定项之间有什么区别?
- 为什么地址运算符是C++类的默认成员,它是什么
- C++:如何使某些类访问其对象中的默认成员?
- 如果std::make_unique从未被调用,为什么它在默认成员初始化中不需要参数
- 使用构造函数作为默认成员值
- 如何防止c++创建默认成员