在类构造函数中调用虚函数

时间:2013-03-07 13:30:46

标签: c++ inheritance

在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(); 
 }

2 个答案:

答案 0 :(得分:1)

调用CB::foo()不是动态调度的,所以等待您或任何阅读此代码的人都不会有任何不幸的惊喜。这很好。事实上,简单地调用foo()也没关系,因为在这种情况下标准相同,尽管你可能想为你的同事留下评论。

答案 1 :(得分: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()之间的区别在于,在第一种情况下,您正在使用动态分派,此时最终将调用函数最终覆盖 < / em>,而在合格的情况下(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" 1}}输入并打印d1。然后执行foo()构造函数,调用base::foo()在此级别选择最终覆盖,仍为d2。完成后,将评估d2::foo()构造函数。此时最终的覆盖是"d2"并打印base base d2 ,产生:

d2

请注意,即使他认为我只创建了我们正在创建的对象类型为base的对象,它也会暂时表现为d1对象,然后表现为d2对象,并且仅在{ {1}}构造函数开始执行它开始表现为d2对象并调用d2。这被许多人认为是令人困惑的。

请注意,因为每个级别的对象的 dynamic 类型正是要计算的构造函数的类型,所以最终的覆盖将始终被分派到该类型。除了处理......之外,添加额外的资格并没有多大区别。

纯虚拟功能

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

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中对[*]的无限制调用生成错误的唯一情况,因为正在评估该构造函数时foo是纯虚拟的,并且没有 final超控器。另一方面,添加限定禁用动态调度,上面的代码将编译并运行。另请注意,在derived构造函数中,您可以使用额外的限定条件来选择函数base::foo的特定定义,该定义可能不是此级别的最终覆盖者。上面的代码打印:

base
derived
base