当派生类仅重写所有方法的子集时,为什么会出现 C++ 编译错误,所有方法都具有相同的名称但不同的签名(重载)

问题描述 投票:0回答:1

简化后,您有一个接口基类 A,它呈现一个多态

method()
,一个派生类 B,它实现了其中一些
method()
的细节。然后一些外部函数调用这些函数,依赖于从 B 类实例的角度可见的所有 `method() 签名,并且您的编译器(在我的例子中为 MSVC2022)出错,报告它无法将接口与中提供的参数类型相匹配。你的职能:

class A {
public:
  virtual void method(int x) = 0;
  virtual void method(double x) = 0;
  virtual void method(const char *x) = 0;

  // watch this one:
  virtual void method(const std::string &x);
};

class B : public A {
public:
  // we only override the first three of those as those were supposed to be implemented 
  // in a derived class like this one!
  virtual void method(int x) override;
  virtual void method(double x) override;
  virtual void method(const char *x) override;
};

// and then there's a few more flavours of B around...


void outsider_calling_in(T idx, const std::string &arg) {
  // digs up only instance of type B:
  B &record = dig_up_record_instance<B>(idx);

  record.method(arg);    // -- ** compiler barfs error **
  // ^^^ SHOULD have matched A::method(const string &x) but we're not so lucky.
}

void outsider_calling_in(T idx, int arg) {
  B &record = dig_up_record_instance<B>(idx);

  record.method(arg);    // A-okay!
  // ^^^ matches B::method(int x) and we're off to the races!
}

我一直在想我做错了什么......

c++ inheritance c++17 overloading
1个回答
0
投票

好吧,在这里回答我自己的问题——我将其发布在这里,因为我花了很多时间来找出答案,并且我希望有一天其他人也会遭受同样的命运;几个月来我一直在使用一种hacky替代方法(重命名非覆盖的

method(const std::string &)
变体,ugh!),直到我偶然发现了这个问题的答案:

为什么具有相同名称但不同签名的多个继承函数不会被视为重载函数?

这个问题是关于多重继承,而这根本不是,但是当我读到“第 10.2/2 节”段落时,因为我当时不知道还能做什么,我震惊了我认为前几行也适用于这种情况。引用:


第 10.2/2 节

以下步骤定义了类作用域 C 中名称查找的结果。首先,考虑类及其每个基类子对象中名称的每个声明。如果 A 是 B 的基类子对象,则一个子对象 B 中的成员名称 f 会隐藏子对象 A 中的成员名称 f。

任何如此隐藏的声明都将被排除在考虑范围之外。 这些声明中的每一个声明由 using 声明引入的 被认为来自 C 的每个子对象,该子对象的类型包含由 using 声明指定的声明。如果声明的结果集并非全部来自同一类型的子对象,或者该集合具有非静态成员并包含来自不同子对象的成员,则存在歧义,并且程序格式错误。否则该集合就是查找的结果。


这为我们提供了以下解决方案来解决这个“不可见”问题:添加一个

using

 语句:

class A { public: virtual void method(int x) = 0; virtual void method(double x) = 0; virtual void method(const char *x) = 0; // watch this one: virtual void method(const std::string &x); }; class B : public A { public: // we only override the first three of those as those were supposed to be implemented // in a derived class like this one! virtual void method(int x) override; virtual void method(double x) override; virtual void method(const char *x) override; // now make sure the extra method() flavours from A are available here as well: using A::method; }; void outsider_calling_in(T idx, const std::string &arg) { // digs up only instance of type B: B &record = dig_up_record_instance<B>(idx); record.method(arg); // *pass!* / *profit!* // ^^^ now *does* match A::method(const string &x) and we're off... } void outsider_calling_in(T idx, int arg) { B &record = dig_up_record_instance<B>(idx); record.method(arg); // A-okay, as before! // ^^^ matches B::method(int x) and we're off to the races! }
对于实际情况:请参阅提交差异中的此更改:

https://github.com/GerHobbelt/tesseract/commit/4a08d1a6eacfd0026d5f02a64737f7df7b7583db,这是一组用于管理各种配置设置的“Param”类,然后我们可以还跟踪它们的使用情况和功能。回答以下问题:“今天使用了哪些设置,使用频率如何?”; “我们经常摆弄那个吗?”等等,这样我们就可以从无数可以旋转的旋钮的混乱中得到一些干草。

无论如何,所有的荣誉都应该归于

为什么具有相同名称但不同签名的多个继承函数不会被视为重载函数? !

© www.soinside.com 2019 - 2024. All rights reserved.