【问题标题】:Explicitly stop late binding显式停止后期绑定
【发布时间】:2017-06-05 13:11:49
【问题描述】:

如果我们创建一个指向其子类对象的基类类的对象指针,那么我们使用虚拟关键字进行后期绑定 所以,在后期绑定的情况下,我们的代码是这样的:-

#include<iostream>
using namespace std;
struct A{
    virtual void print() {
        cout<<"function1";
    }
};

struct B : public A{
    void print(){
        cout<<"function2";
    } 
};

struct C : public B{
    void print(){
        cout<<"function3";
    } 
};

int main(){
    A* a = new C();
    A* p = new B();
    a->print();
    p->print();
} 

现在我的问题是:当我们在基类中使用 virtual 关键字时,在基类中创建的派生类的所有功能都将变为虚拟。 在多级继承中,有什么方法可以阻止类 c 的函数是虚拟的? 有什么办法可以打破这个虚函数链? 抱歉有任何错误,但我尽力了..☺️☺️

【问题讨论】:

  • 来自C::print() 你可以打电话给B::print() 有帮助吗?
  • 这听起来像XY problem。您要解决的真正问题是什么?
  • @Default 这不是重复的,OP 似乎仍然希望能够继承该类,但防止方法被覆盖。您链接到的问题的答案完全阻止了继承。
  • 你说它不是重复的很有趣,@Pharap,因为该问题的公认答案与您对该问题的答案几乎完全相同。 (除非你假设 C++11;Nawaz 不假设。)
  • 您在寻找final 吗?

标签: c++


【解决方案1】:

不可能在子类中使已经是virtual 的函数不是virtual

虚拟性是顶级基类的属性,而不是子类的属性。一旦方法被标记为virtual,并且指向该类的指针在调用时必须对该函数使用动态调度,因为该指针可能指向已覆盖该行为的子类。

考虑这段代码:

A a;
B b;
C c;

A * ap = &a;
A * bp = &b;
A * cp = &c;

ap->print(); // 'function1'
bp->print(); // 'function2'
cp->print(); // 'function3'

这里,print 的调用不能告诉编译时调用哪个函数,它们绝对必须使用动态调度。

但是,您可以使 C::print 的行为类似于 A::print

struct C : public B {
    void print() {
        A::print();
    }
};

结果:

ap->print(); // 'function1'
bp->print(); // 'function2'
cp->print(); // 'function1'

如果A::print() 的行为发生变化,C::print() 会反映这些变化。

这仍然是可覆盖的,除非您使用如下所述的 final 关键字。


原答案:

我相信您正在寻找 final 说明符。 不过,它仅适用于 C++11。

引用 en.cppreference 关于final specifier 的页面:

在虚函数声明或定义中使用时,final 确保函数是虚拟的并指定它可能不是 被派生类覆盖。程序格式不正确(a 编译时错误),否则。

以及他们给出的示例的变体,展示了您的问题的解决方案:

struct A
{
    virtual void foo();
};

struct B : A
{
    void foo() final; // B::foo is overridden and it is the final override
};

struct C : B
{
    void foo() override; // Error: foo cannot be overridden as it's final in B
};

【讨论】:

  • final 只是使定义函数成为非法。 OP 想要的是仍然能够制作 B::foo 但它不是虚拟的。
  • final 将允许编译器在许多情况下对foo() 的调用进行去虚拟化。这是你能做的最好的。在派生类中不能使虚函数成为非虚函数。
  • @AndyG 确切的问题是“有什么办法可以阻止 c 类的函数变为虚拟函数吗?”这正是最终专家所做的。 OP 没有问“我们如何访问父级对 foo 的定义?”。
  • @Pharap:如果您尝试定义最终说明符,它不会使函数成为非虚拟函数,它只会使另一个派生类覆盖它是非法的。查看error message here: "error: virtual function 'virtual void C::print()'"
  • @AndyG 我假设“非虚拟”的 OP 意味着“不能被覆盖”。这个问题是模棱两可的,我们所能做的就是等待澄清OP的意图是什么。
猜你喜欢
  • 2021-06-22
  • 2016-07-16
  • 2011-04-23
  • 1970-01-01
  • 2011-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-15
相关资源
最近更新 更多