覆盖合格的虚拟方法
我有C++类与多个父母;每个家长定义了一个共同的名字,但不同目的的功能:覆盖合格的虚拟方法
class BaseA
{
virtual void myFunc(); // does some task
};
class BaseB
{
virtual void myFunc(); // does some other task
};
class Derived : public BaseA, public BaseB;
如果是这样的话,我也没问题 - 我能解决多义它使用语句,我可以选择哪些一个使用基类名称和范围解析运算符进行调用。
不幸的是,派生类需要重写他们两个:
class Derived : public BaseA, public BaseB
{
virtual void BaseA::myFunc(); // Derived needs to change the way both tasks are done
virtual void BaseB::myFunc();
}
这是不行的,而不是因为它引入了一个新的不确定性(尽管可能),但由于
“错误C3240:'myFunc':必须是非重载抽象成员函数'BaseA'“
”错误C2838:成员声明中的非法限定名称“
在不同的情况下,我可能会重命名这些方法,或者使它们像编译器所建议的那样是纯虚拟的。但是,班级层次结构和一些外部问题使得第一个选项难度很大,第二个不可能。
有没有人有建议?为什么限定符只允许纯虚拟方法?有什么方法可以同时覆盖虚拟方法和解决歧义?
Microsoft allows that syntax(它从Visual C++ 2005开始)。 They also introduced a new, more powerful syntax for managed code only。
C++ 0x中不包含任何一个。
见http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2108.html
我认为这是一个解决办法:
class BaseA
{
protected:
virtual void myFunc(); // does some task
};
class BaseB
{
protected:
virtual void myFunc(); // does some other task
};
class ShimA : virtual BaseA
{
virtual void myFunc() { myFuncA(); }
protected:
virtual void myFuncA() { BaseA::myFunc(); }
};
class ShimB : virtual BaseB
{
virtual void myFunc() { myFuncB(); }
protected:
virtual void myFuncB() { BaseB::myFunc(); }
};
class Derived : public virtual BaseA, public virtual BaseB, protected ShimA, protected ShimB
{
virtual void myFuncA() {}
virtual void myFuncB() {}
};
这是multiple inheritance的一个大问题。如果您有多个相同名称的函数被继承以确定哪一个函数应该被覆盖,总会遇到问题,请参阅The Diamond Problem。由于函数语法(函数名称和运算符)必须是唯一的,因此无法重写它们。
您可以使用组合对象。
class Derived : public BaseB {
struct temp : public BaseA {
virtual void myFunc() {
d->BaseAMyFunc();
}
Derived* d;
};
temp t;
public:
Derived() {
t.d = this;
}
operator BaseA&() { return temp; }
operator const BaseA&() const { return temp; }
void myFunc(); // refers to BaseB::myFunc()
void BaseAMyFunc(); // called when BaseA::myFunc() is called.
}
这不是特别整洁,它有点受限,但它在某些情况下有效。
我意识到这个问题是旧的,但它有很多的意见,并没有解决一个干净的方式这如果你是接口的作者。许多人认为虚拟接口应该具有公共的非虚拟功能,这些虚拟功能在内部遵循私有虚拟功能(我同意他们)。这有几个好处,他们是说非虚拟名称可以有,因为他们更强烈地绑定到该接口不同的含义之一:
struct BaseA
{
virtual ~BaseA() = default;
void func()
{
handle_a_func();
}
private:
virtual void handle_a_func() = 0;
};
struct BaseB
{
virtual ~BaseB() = default;
int func() const // note the different signature and return type
{
handle_b_func();
}
private:
virtual int handle_b_func() const = 0;
};
// now provide an implementation
struct ABImpl : public BaseA, public BaseB
{
ABImpl() {}
private:
void handle_a_func() override final
{
// alter some state
}
int handle_b_func() const override final
{
return _x;
}
int _x = 0;
};
// now use the class
auto ab = make_shared<ABImpl>();
auto a = static_pointer_cast<BaseA>(ab);
auto b = static_pointer_cast<const BaseB>(ab);
a->func(); // uses A's mutable interface
auto x = b->func(); // uses B's const interface
这种方法的另一个好处是,基类的实现可以管理像互斥和哨兵代表的衍生的功能,例如:
struct base {
void do() {
std::unique_lock<std::mutex> l(_m);
handle_do();
}
private:
virtual void handle_do() = 0;
std::mutex _m;
};
另一个优点是,一些有用的*功能运营商仅需要执行一次对整个类层次结构定义:
struct base
{
void write_to(std::ostream& os) const {
// lock a mutex here?
handle_write(os);
private:
virtual void handle_write(std::ostream& os) const {
os << "write base class info here\n";
}
};
inline std::ostream& operator<<(std::ostream& os, const base& b) {
b.write_to(os);
return os;
}
struct derived : base {
private:
virtual void handle_write(std::ostream& os) const override {
base::handle_write(os); // handle base class implementation
std::cout << "write relevant data here. We could still be overridden safely\n";
}
};
// write any derived class like this:
auto b = unique_ptr<base> { new derived() };
cout << "here is a kind-of b:\n" << *b << endl;
您也可以重写单独的类中的行为:'DerivedA:public BaseA','DerivedB:public BaseB',然后'派生:public DerivedA,public DerivedB'。这并不解决歧义问题,但 – Cameron 2011-03-30 03:23:14