operator== 标记为 'override',但不会覆盖
operator== marked 'override', but does not override
我在覆盖基础 class 运算符== 时遇到问题。这是代码。
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class IClient {
virtual const std::vector<T>& getID() = 0;
virtual bool isEqual(const std::vector<T>& anotherID) = 0;
virtual bool operator==(const IClient& anotherClient) = 0;
};
class SeviceClient : public IClient<int8_t> {
const std::vector<int8_t> ID;
public:
SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}
const std::vector<int8_t>& getID() override {
return ID;
}
bool isEqual(const std::vector<int8_t>& anotherID) override {
return true;
}
bool operator==(const SeviceClient& anotherClient) override {
return true;
}
};
它抱怨
error: 'bool SeviceClient::operator==(const SeviceClient&)' marked 'override', but does not override
当我将函数转换为
时,编译器看起来很开心
bool operator==(const IClient<int8_t>& anotherClient) override {}
这是问题的解决方案还是我遗漏了什么?
谢谢
SeviceClient 和 IClient 是不同的类型。
所以,bool SeviceClient::operator==(const SeviceClient&) 没有基础声明。
你必须明白 C++ 有可能重载函数。
因此,要识别假设被调用的函数,不仅函数名称必须匹配,而且参数类型也必须匹配。当然有隐式转换可以调整参数以匹配函数参数类型,但请注意,如果有多个同名函数,则隐式转换会导致歧义。
如果您正在使用多态性,那么您必须记住子 class 应该可用,因为它只是父 class。持有指向 base class 指针的人应该不会注意到它实际上是一个 subclass.
所以当你重写虚函数时,参数的类型必须非常准确,所以一切都是明确的。
我怀疑您需要静态多态性和 CRTP 而不是动态多态性。所以像这样:
template <typename Child, typename T>
class IClient {
const std::vector<T>& getID() {
return asChild()->getID();
}
bool isEqual(const std::vector<T>& anotherID) {
return asChild()->isEqual(anotherID);
}
bool operator==(const Child& anotherClient) {
return asChild()->isEqual(anotherClient);
}
private:
Child* asChild() {
return static_cast<Child*>(this);
}
const Child* asChild() const {
return static_cast<const Child*>(this);
}
};
class SeviceClient : public IClient<SeviceClient, int8_t> {
const std::vector<int8_t> ID;
public:
SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}
const std::vector<int8_t>& getID() {
return ID;
}
bool isEqual(const std::vector<int8_t>& anotherID) {
return true;
}
bool operator==(const SeviceClient& anotherClient) {
return true;
}
};
这个问题有两个方面。一、这个设计违反了C++的哪些规则?第二,为什么C++有这样的规则?
第一个很简单。您可以用具有完全相同参数列表的函数覆盖函数。由于 (const IClient& anotherClient)
与 (const SeviceClient& anotherClient)
不完全相同,因此不会发生覆盖。结案。
第二个有点复杂。为了理解它,让我们使用更熟悉的 class 层次结构。有class Animal
,有class Dog : public Animal
,还有class Cat : public Animal
。
bool Animal::operator==(const Animal&)
告诉我们什么?它告诉我们可以将一种动物与另一种动物进行比较。特别是,我们可以比较狗和狗,猫和猫,狗和猫,老鼠和蝙蝠,鱼和蚊子,土豚和霸王龙。这是 class Animal
给你的承诺。如果我们有两个 Animal
对象,我们可以比较它们。
现在,覆盖此运算符的函数应该可以实现承诺。 bool Dog::operator==(const Dog&)
会那样做吗?不,它实现了一个更狭窄的承诺:这个 Animal
(恰好是 Dog
)可以与 Dog
进行比较。履行这个狭隘的承诺合法吗?绝对地。假装这个功能也实现了能够比较任何两种动物的广泛承诺是否合法?绝对不。所以我们可以声明这个函数,但不能声称它覆盖了 Animal
相等运算符。
如果有一条规则允许我们这样声明会怎样?
Dog d;
Cat c;
Animal& da = d;
Animal& ca = c;
std::cout << (da == ca);
这个程序片段必须编译,因为每一行都是有效的(根据我们的幻想规则),但是它应该做什么?没有比较狗和猫的代码!
有些语言说“好的,没什么大不了的,我们只会抛出一个 运行 时间错误”。 C++ 不会那样做。如果您希望上面的代码抛出 运行 次错误,您应该自己编写代码来抛出 运行 次错误。这意味着用 bool Dog::operator==(const Animal&)
和 bool Cat::operator==(const Animal&)
覆盖 bool Animal::operator==(const Animal&)
,并检查那里的错误情况。
虽然这可能不是一个好主意。对于 class 层次结构,平等通常毫无意义。通常最好完全省略比较,或者使其成为非虚拟的并仅在子 classes 中定义。
我在覆盖基础 class 运算符== 时遇到问题。这是代码。
#include <iostream>
#include <vector>
using namespace std;
template <typename T>
class IClient {
virtual const std::vector<T>& getID() = 0;
virtual bool isEqual(const std::vector<T>& anotherID) = 0;
virtual bool operator==(const IClient& anotherClient) = 0;
};
class SeviceClient : public IClient<int8_t> {
const std::vector<int8_t> ID;
public:
SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}
const std::vector<int8_t>& getID() override {
return ID;
}
bool isEqual(const std::vector<int8_t>& anotherID) override {
return true;
}
bool operator==(const SeviceClient& anotherClient) override {
return true;
}
};
它抱怨
error: 'bool SeviceClient::operator==(const SeviceClient&)' marked 'override', but does not override
当我将函数转换为
时,编译器看起来很开心bool operator==(const IClient<int8_t>& anotherClient) override {}
这是问题的解决方案还是我遗漏了什么?
谢谢
SeviceClient 和 IClient 是不同的类型。 所以,bool SeviceClient::operator==(const SeviceClient&) 没有基础声明。
你必须明白 C++ 有可能重载函数。 因此,要识别假设被调用的函数,不仅函数名称必须匹配,而且参数类型也必须匹配。当然有隐式转换可以调整参数以匹配函数参数类型,但请注意,如果有多个同名函数,则隐式转换会导致歧义。
如果您正在使用多态性,那么您必须记住子 class 应该可用,因为它只是父 class。持有指向 base class 指针的人应该不会注意到它实际上是一个 subclass.
所以当你重写虚函数时,参数的类型必须非常准确,所以一切都是明确的。
我怀疑您需要静态多态性和 CRTP 而不是动态多态性。所以像这样:
template <typename Child, typename T>
class IClient {
const std::vector<T>& getID() {
return asChild()->getID();
}
bool isEqual(const std::vector<T>& anotherID) {
return asChild()->isEqual(anotherID);
}
bool operator==(const Child& anotherClient) {
return asChild()->isEqual(anotherClient);
}
private:
Child* asChild() {
return static_cast<Child*>(this);
}
const Child* asChild() const {
return static_cast<const Child*>(this);
}
};
class SeviceClient : public IClient<SeviceClient, int8_t> {
const std::vector<int8_t> ID;
public:
SeviceClient(const std::vector<int8_t>& ID) : ID(std::move(ID)) {}
SeviceClient(const std::vector<int8_t>&& ID) : ID(std::move(ID)) {}
const std::vector<int8_t>& getID() {
return ID;
}
bool isEqual(const std::vector<int8_t>& anotherID) {
return true;
}
bool operator==(const SeviceClient& anotherClient) {
return true;
}
};
这个问题有两个方面。一、这个设计违反了C++的哪些规则?第二,为什么C++有这样的规则?
第一个很简单。您可以用具有完全相同参数列表的函数覆盖函数。由于 (const IClient& anotherClient)
与 (const SeviceClient& anotherClient)
不完全相同,因此不会发生覆盖。结案。
第二个有点复杂。为了理解它,让我们使用更熟悉的 class 层次结构。有class Animal
,有class Dog : public Animal
,还有class Cat : public Animal
。
bool Animal::operator==(const Animal&)
告诉我们什么?它告诉我们可以将一种动物与另一种动物进行比较。特别是,我们可以比较狗和狗,猫和猫,狗和猫,老鼠和蝙蝠,鱼和蚊子,土豚和霸王龙。这是 class Animal
给你的承诺。如果我们有两个 Animal
对象,我们可以比较它们。
现在,覆盖此运算符的函数应该可以实现承诺。 bool Dog::operator==(const Dog&)
会那样做吗?不,它实现了一个更狭窄的承诺:这个 Animal
(恰好是 Dog
)可以与 Dog
进行比较。履行这个狭隘的承诺合法吗?绝对地。假装这个功能也实现了能够比较任何两种动物的广泛承诺是否合法?绝对不。所以我们可以声明这个函数,但不能声称它覆盖了 Animal
相等运算符。
如果有一条规则允许我们这样声明会怎样?
Dog d;
Cat c;
Animal& da = d;
Animal& ca = c;
std::cout << (da == ca);
这个程序片段必须编译,因为每一行都是有效的(根据我们的幻想规则),但是它应该做什么?没有比较狗和猫的代码!
有些语言说“好的,没什么大不了的,我们只会抛出一个 运行 时间错误”。 C++ 不会那样做。如果您希望上面的代码抛出 运行 次错误,您应该自己编写代码来抛出 运行 次错误。这意味着用 bool Dog::operator==(const Animal&)
和 bool Cat::operator==(const Animal&)
覆盖 bool Animal::operator==(const Animal&)
,并检查那里的错误情况。
虽然这可能不是一个好主意。对于 class 层次结构,平等通常毫无意义。通常最好完全省略比较,或者使其成为非虚拟的并仅在子 classes 中定义。