重写限定的虚拟方法 我有多个家长的C++类;每个父级定义一个具有通用名称但用途不同的函数: class BaseA { virtual void myFunc(); // does some task }; class BaseB { virtual void myFunc(); // does some other task }; class Derived : public BaseA, public BaseB;
如果是这样的话,我就没有问题了——我可以用using语句解决它的模糊性,并且我可以使用基类名称和范围解析操作符选择调用哪一个 不幸的是,派生类需要同时重写它们:重写限定的虚拟方法 我有多个家长的C++类;每个父级定义一个具有通用名称但用途不同的函数: class BaseA { virtual void myFunc(); // does some task }; class BaseB { virtual void myFunc(); // does some other task }; class Derived : public BaseA, public BaseB;,c++,virtual-functions,ambiguity,C++,Virtual Functions,Ambiguity,如果是这样的话,我就没有问题了——我可以用using语句解决它的模糊性,并且我可以使用基类名称和范围解析操作符选择调用哪一个 不幸的是,派生类需要同时重写它们: class Derived : public BaseA, public BaseB { virtual void BaseA::myFunc(); // Derived needs to change the way both tasks are done virtual void BaseB::myFunc(); }
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:成员声明中的限定名非法”
在不同的情况下,我可能只是重命名这些方法,或者按照编译器的建议将它们变成纯虚拟的。然而,类层次结构和许多外部问题使得第一个选项非常困难,第二个选项不可能
有人有什么建议吗?为什么限定符只允许用于纯虚拟方法?有什么方法可以同时覆盖虚拟方法和解决歧义吗?这是虚拟方法的一个大问题。当您继承了多个同名函数以确定应该覆盖哪个函数时,总会出现问题请参见。由于函数语法(函数名和运算符)必须是唯一的,因此不能同时重写这两个函数 您可以使用合成对象
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.
}
这不是特别整洁,它有点限制,但它确实在某些情况下工作。
(它在Visual C++ 2005中可用)p> C++0x中没有包含任何一个
看我认为这是一个解决办法:
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() {}
};
我意识到这个问题由来已久,但它有很多观点,如果你是接口的作者,有一个干净的方法来解决这个问题 许多人认为虚拟接口应该具有公共的非虚拟功能,这些功能在内部遵从私有的虚拟功能(我同意他们的观点)。这有几个优点,其中之一是非虚拟名称可以有不同的含义,因为它们与接口的绑定更为紧密:
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 BaseA
{
virtual~BaseA()=默认值;
void func()
{
handle_a_func();
}
私人:
虚空句柄_a_func()=0;
};
结构BaseB
{
virtual~BaseB()=默认值;
int func()const//注意不同的签名和返回类型
{
handle_b_func();
}
私人:
虚整数句柄函数()常量=0;
};
//现在提供一个实现
结构ABImpl:public BaseA,public BaseB
{
ABImpl(){}
私人:
void handle_a_func()重写final
{
//改变某种状态
}
int handle_b_func()常量重写final
{
返回x;
}
int x=0;
};
//现在使用这个类
自动ab=使_共享();
自动a=静态指针投射(ab);
自动b=静态指针投射(ab);
a->func();//使用A的可变接口
自动x=b->func();//使用B的const接口
这种方法的另一个优点是,基类实现可以代表派生函数管理互斥体和Sentinel,例如:
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 do(){
std::唯一锁l(_m);
handle_do();
}
私人:
虚空句柄_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;
struct base
{
无效写入(std::ostream&os)常量{
//在这里锁定互斥锁?
操作系统;
私人:
虚空句柄写入(std::ostream&os)常量{
os您还可以覆盖单独类中的行为:DerivedA:public BaseA
,DerivedB:public BaseB
,然后Derived:public DerivedA,public DerivedB
。这并不能解决歧义问题,尽管感谢MS语法的信息;不幸的是,它只适用于抽象基类(注意示例中的“\uuuu接口”关键字)@John:managed variant适用于从基类继承的虚拟方法。不管怎样,看看我的编辑,我认为这应该可以解决你的问题。再次感谢。你的建议行得通,但我的情况的细节阻止我使用它。基本上,我正在为一些反向工程代码编写一个类定义,我实际上是c不改变继承结构或虚函数表的组成(或明显使用托管C++)