重写限定的虚拟方法 我有多个家长的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++类;每个父级定义一个具有通用名称但用途不同的函数: 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(); }

如果是这样的话,我就没有问题了——我可以用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();
}
这不起作用,不是因为它引入了新的歧义(尽管可能),而是因为

“错误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++)