0

我想知道是否可以从基构造函数调用的函数中调用派生类函数(在执行括号中的代码时不应该已经创建它吗?)

#pragma once
class ClassA
{
public:
 ClassA(void);
 virtual ~ClassA(void);

 void Init();

protected:
 short m_a;
 short m_b;

 virtual void SetNumbers(short s);
};

include "ClassA.h"
#include <iostream>


ClassA::ClassA(void) : m_a(0), m_b(0)
{
Init();
}


ClassA::~ClassA(void)
{
}

void ClassA::SetNumbers(short s)
{
 std::cout << "In ClassA::SetNumbers()\n";
 m_a = s;
 m_b = s;
}

void ClassA::Init()
{
 this->SetNumbers(2);
}

#pragma once
#include "ClassA.h"
class ClassB : public ClassA
{
public:
 ClassB(void);
 virtual ~ClassB(void);

 virtual void SetNumbers(short);

 int x;
};

#include "ClassB.h"
#include <iostream>


ClassB::ClassB(void)
{
}


ClassB::~ClassB(void)
{
}

void ClassB::SetNumbers(short s)
{
 std::cout << "In ClassB::SetNumbers()\n";

 m_a = ++s;
 m_b = s;

 ClassA::SetNumbers(s);
}

有什么建议怎么做吗?...

先感谢您 :)...

4

5 回答 5

2

您不能这样做,原因很简单,即在构造基类时,派生类甚至还没有开始构造。您不能在(尚)不存在的对象上调用成员函数。

在实践中,即使您SetNumbers在派生类的成员变量初始化之前设法调用并分配它们,它们在最终被初始化时肯定会被覆盖。我承认对此进行推理有点毫无意义,因为我们将完全超出定义的行为。

于 2010-08-18T19:03:45.553 回答
2

不,B 的所有部分(从 A 开始,因为它是基础)都是在调用 B 的构造函数之前构造的。所以,到SetNumbers调用的时候,B 的任何部分(除了 A 部分)都没有被构造 --- 这可能包括 v-table,所以没有办法知道调用会去哪里。

当然,有一个简单的解决方案:在 B 的构造函数中调用 B::SetNumber() (毕竟是 B 的构造函数的目的)

于 2010-08-18T19:04:26.640 回答
1

不,对不起。:( 它可能会在一两个 C++ 编译器中编译,但不建议这样做。来自C++ FAQ Lite 第 10.7 节

[10.7] 你应该在构造函数中使用this指针吗?

[……剪断……]

这是永远不会起作用的东西: 构造函数(或从构造函数调用的函数)的 {body} 不能通过调用在派生类中被覆盖的虚拟成员函数来得到派生类。如果您的目标是获取派生类中的覆盖函数,那么您将得不到您想要的。请注意,无论您如何调用虚成员函数,您都不会得到派生类中的覆盖:显式使用 this 指针(例如,this->method()),隐式使用 this 指针(例如,method( )),甚至调用一些其他函数来调用 this 对象上的虚拟成员函数。底线是这个:即使调用者正在构造派生类的对象,在基类的构造函数期间,您的对象还不属于该派生类。你被警告了。

注意:强调我的。

更多详情见链接

于 2010-08-18T19:09:18.497 回答
1

唯一可以这样做的情况是,某些东西是从一个自己参数化的模板派生而来的:

template<typename T> class base
{
  T* down_cast() throw()
  {
    return static_cast<Derived*>(this);
  }
  const T* down_cast() const throw()
  {
    return static_cast<const Derived*>(this);
  }
public:
  base()
  {
    down_cast()->doSomething();
  }
 /* … */
};

class derived : private base<derived>
{
public:
  void doSomething()
  {
  }
};

请注意,它doSomething是公共的,而不是虚拟的。

我们可以将 static_cast 转换为派生,因为已知派生是派生类型。

在最好的情况下,从自己参数化的基础中派生一些东西是一件奇怪的事情。据说微软的 ATL 团队使用它时,他们问过 C++ 编译器团队是否有效,但没有人确定,尽管它是有效的,因为模板构造取决于名称,如下所示:

首先,模板可用,但未在类中使用。然后,derived可用的名称。然后它实例化布局base<derived>——这需要成员变量和虚函数的知识,只要这些都不依赖于derived布局的知识(指针和引用都可以),一切都会好起来的。然后它会创建 的布局derived,最后会创建derived的成员函数,其中可能包括为base<derived>. 因此,只要base<derived>不包含派生成员变量(基类永远不能包含从它们自己派生的类型的成员变量)或需要了解派生布局的虚函数,我们确实可以进行上面看起来很冒险的继承.

This includes being able to call non-virtual public members of derived from base during construction, because it's already part of base. There are strong limitations on this. In particular, if doSomething() depends on anything constructed in derived's constructor it won't work as derived hasn't been constructed yet.

Now, is this actually a good idea? No.

于 2010-08-18T19:27:06.257 回答
0

一个简单的设计解决方案是使用聚合而不是继承

于 2010-08-18T19:11:36.560 回答