是否可以重载(影子)虚函数?
Is it possible to overload (shadow) a virtual function?
我想隐藏一个基础class的虚函数,并引入一个新的具有相同名称和相同签名的虚函数,除了return类型。
类似于:
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() final { return 1; } // Overriding A::f.
};
struct C: public B {
virtual double f() = 0; // Newly introduced method C::f. It shadows A::f
};
struct D: public C {
double f() final { return 2.0; } // Overriding C::f.
};
我希望它的行为如下:
D d;
ASSERT( static_cast<D&>(d).f() == 2.0 );
ASSERT( static_cast<C&>(d).f() == 2.0 );
ASSERT( static_cast<B&>(d).f() == 1 );
ASSERT( static_cast<A&>(d).f() == 1 );
有可能实现吗?
任何版本的 C++ 标准都可以。
不更改函数签名(return 类型不是其中的一部分)就不可能重载。但是由于默认的函数参数,我们可以有不同的签名,但仍然使用相同数量的参数调用。使用像 C++20 的 std::type_identity
之类的东西(虽然可以在任何标准中轻松实现),曾经可以写
struct A {
virtual int f(std::type_identity<int> = {}) = 0;
};
struct B: public A {
int f(std::type_identity<int> = {}) final { return 1; }
};
struct C: public B {
virtual double f(std::type_identity<double> = {}) = 0;
};
struct D: public C {
double f(std::type_identity<double> = {}) final { return 2.0; }
};
每个重载现在都标有其 return 类型,从而赋予每个重载不同的签名。但是默认参数 {}
可以通过 f()
调用它们。由于名称隐藏,空参数列表的重载集没有冲突。
如果你不让 C
直接继承自 B
,而是引入继承自 B
和 D
的 E
,你可以有不同的 f()
s 并用 static_cast
s 消除它们之间的歧义。
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() override final { return 1; } // Overriding A::f.
};
struct C {
virtual double f() = 0; // Newly introduced method C::f
};
struct D: public C {
double f() override final { return 2.0; } // Overriding C::f.
};
struct E : public B, public D { // inherit from both B and D
};
int main() {
E foo;
std::cout << static_cast<A&>(foo).f() << '\n'; // 1
std::cout << static_cast<B&>(foo).f() << '\n'; // 1
std::cout << static_cast<C&>(foo).f() << '\n'; // 2
std::cout << static_cast<D&>(foo).f() << '\n'; // 2
}
我想隐藏一个基础class的虚函数,并引入一个新的具有相同名称和相同签名的虚函数,除了return类型。
类似于:
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() final { return 1; } // Overriding A::f.
};
struct C: public B {
virtual double f() = 0; // Newly introduced method C::f. It shadows A::f
};
struct D: public C {
double f() final { return 2.0; } // Overriding C::f.
};
我希望它的行为如下:
D d;
ASSERT( static_cast<D&>(d).f() == 2.0 );
ASSERT( static_cast<C&>(d).f() == 2.0 );
ASSERT( static_cast<B&>(d).f() == 1 );
ASSERT( static_cast<A&>(d).f() == 1 );
有可能实现吗?
任何版本的 C++ 标准都可以。
不更改函数签名(return 类型不是其中的一部分)就不可能重载。但是由于默认的函数参数,我们可以有不同的签名,但仍然使用相同数量的参数调用。使用像 C++20 的 std::type_identity
之类的东西(虽然可以在任何标准中轻松实现),曾经可以写
struct A {
virtual int f(std::type_identity<int> = {}) = 0;
};
struct B: public A {
int f(std::type_identity<int> = {}) final { return 1; }
};
struct C: public B {
virtual double f(std::type_identity<double> = {}) = 0;
};
struct D: public C {
double f(std::type_identity<double> = {}) final { return 2.0; }
};
每个重载现在都标有其 return 类型,从而赋予每个重载不同的签名。但是默认参数 {}
可以通过 f()
调用它们。由于名称隐藏,空参数列表的重载集没有冲突。
如果你不让 C
直接继承自 B
,而是引入继承自 B
和 D
的 E
,你可以有不同的 f()
s 并用 static_cast
s 消除它们之间的歧义。
struct A {
virtual int f() = 0; // Newly introduced method: A::f.
};
struct B: public A {
int f() override final { return 1; } // Overriding A::f.
};
struct C {
virtual double f() = 0; // Newly introduced method C::f
};
struct D: public C {
double f() override final { return 2.0; } // Overriding C::f.
};
struct E : public B, public D { // inherit from both B and D
};
int main() {
E foo;
std::cout << static_cast<A&>(foo).f() << '\n'; // 1
std::cout << static_cast<B&>(foo).f() << '\n'; // 1
std::cout << static_cast<C&>(foo).f() << '\n'; // 2
std::cout << static_cast<D&>(foo).f() << '\n'; // 2
}