2

在 C++ 中,我们不应该调用构造函数/析构函数虚函数。

如果我在类范围内显式调用这些函数怎么办?

本质上,我们是在说我们不想从虚拟中获利。

下面的伪代码正确吗?

 struct CA{ 
    CA(){ CA::foo();} // calling foo() without CA is wrong
    virtual int foo(){} 
 };

 struct CB{ 
    CB(){ CB::foo();} // calling foo() without CB is wrong
    virtual int foo(); 
 }
4

2 回答 2

1

该调用CB::foo()不是动态分派的,因此没有不幸的惊喜在等待您或任何阅读此代码的人。完全没问题。实际上,也可以简单地调用foo(),因为在这种情况下这与标准相同,尽管您可能想为您的同事留下评论。

于 2013-03-07T13:34:44.083 回答
1
struct CA{ 
   CA(){ CA::foo(); } // calling foo() without CA is wrong
   virtual int foo(){}
};

struct CB { 
   CB(){ CB::foo(); } // calling foo() without CB is wrong
   virtual int foo(); 
};

我看不出这两个类之间有任何明显的区别,考虑到必须在程序中定义非纯虚函数,必须在CB::foo某个地方定义,并且它是在类定义中定义还是无关紧要别的地方。

在这两种情况下,调用foo()(没有明确的限定)都是错误的。foo()使用和之间的区别在于Type::foo(),在第一种情况下,您使用的是动态调度,此时最终将调用函数的最终覆盖器而在限定的情况下 ( ),额外的限定禁止动态调度。Type::foo

重要的是要注意此时对象的动态类型在类型层次结构中的构造过程中发生变化。在评估基本构造函数时,动态类型是base,因此最终覆盖器只能从该类中获取。基本构造函数完成后,动态类型将更改为层次结构中的下一个类型,并且可以从这两种类型中选择最终的覆盖器,依此类推。

struct base {
   base() { foo() };
   virtual void foo() { std::cout << "base\n"; }
};
struct d1 : base {
   d1() : base() { foo() };
};
struct d2 : d1 {
   d2() : d1() { foo() };
   virtual void foo() { std::cout << "d2\n"; }
};

类型对象的d2构造将从构造base子对象开始,foo()那里的调用将被分派给最终的覆盖器,此时它只考虑base类型并打印"base". 然后d1执行构造函数,调用foo()在此级别选择最终覆盖器,它仍然是base::foo(). 完成后,对d2构造函数进行评估。在这一点上,最终的覆盖器正在打印d2::foo()"d2"产生:

base
base
d2

请注意,即使我们正在创建的唯一完整对象是 type d2,它也暂时表现为一个base对象,然后作为一个d1对象,并且只有当d2构造函数开始执行时,它才开始表现为一个d2对象并调用d2. 这被许多人认为是令人困惑的。

请注意,因为每个级别的对象的动态类型正是正在评估的构造函数的类型,所以最终的覆盖器将始终被分派给该类型。添加额外的资格并没有太大的区别,除非在处理......

纯虚函数

纯虚函数可以有定义。pure 限定符意味着派生类型必须提供该虚函数的定义,也意味着在执行动态调度时永远不会调用纯虚函数(如果已定义)。在这种特殊情况下,禁用动态调度的额外限定可用于调用该特定实现:

struct base {
   base() { base::foo(); }  // [*]
   virtual void foo() = 0;
};
void base::foo() { std::cout << "base\n"; }
struct derived : base {
   derived() : base() { foo(); base::foo(); }
   virtual void foo() { std::cout << "derived\n"; }
};

foo这是对in的非限定调用格式错误的唯一情况[*],因为当该构造函数被评估时foo是纯虚拟的并且没有最终覆盖器。另一方面,添加限定条件会禁用动态调度,上面的代码将编译并运行。另请注意,在derived构造函数中,您可以使用额外的限定来选择函数的特定定义,该定义base::foo可能不是此级别的最终覆盖器。上面的代码打印:

base
derived
base
于 2013-03-07T14:18:24.907 回答