如何在基类的构造函数中从基类方法调用派生类方法

发布于 2024-09-14 22:20:06 字数 995 浏览 6 评论 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);
}

有什么建议吗? 。

先感谢您 :)...

I am wondering if it is possible to call a derived class´ function from within a function called by the base constructor (shouldn´t it already be created when the code in the brackets are executed?)

#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);
}

Any suggestions how to do it?...

Thank You in advance :)...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

追我者格杀勿论 2024-09-21 22:20:06

不会。B 的所有部分(从 A 开始,因为它是基础)都是在调用 B 的构造函数之前构造的。因此,当调用 SetNumbers 时,B 的任何部分(A 部分除外)都尚未构造完毕 --- 并且可能包括 v 表,因此无法知道它在哪里电话即将接通。

当然,有一个简单的解决方案:从 B 的构造函数中调用 B::SetNumber() (这就是 B 构造函数的用途)

No. All parts of B (starting with A, as it's base) are constructed before B's constructor is called. So, by the time SetNumbers is called, no part of B (except for the A part) has been constructed --- and that may include the v-table, so there's no way to know where that call is going to go.

Of course, there is a simple solution to this: Call B::SetNumber() from within B's constructor (That is, after all, the purpose of B's constructor)

会傲 2024-09-21 22:20:06

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

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

You can't do this for the simple logical reason that while the base class is being constructed, the derived class hasn't even begun to be constructed. You can't call a member function on an object that doesn't exist (yet).

In practice, even if you managed to call SetNumbers and assign to the member variables of the derived class before they were initialized they would surely be overwritten when they finally get initialized. I admit it's a bit pointless to reason about this as we would be well outside defined behaivour.

π浅易 2024-09-21 22:20:06

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

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

[...剪...]

这是永远行不通的东西:
构造函数的 {body} (或
从构造函数调用的函数)
无法通过以下方式深入到派生类
调用一个虚拟成员函数
在派生类中被重写。
如果
你的目标是到达被覆盖的地方
派生类中的函数,您
不会得到你想要的。请注意,您
不会覆盖
派生类独立于你如何
调用虚拟成员函数:
显式使用 this 指针
(例如,this->method()),隐式地
使用 this 指针(例如,
method()),甚至调用其他方法
调用虚拟成员的函数
在你的 this 对象上运行。这
底线是这样的:即使
调用者正在构造一个对象
派生类,在构造函数期间
基类的,你的对象不是
还属于那个派生类。
你有
已被警告。

注意:强调我的。

更多详情请见链接

No, sorry. :( It might compile in one or two C++ compilers, but it's not recommended. From the C++ FAQ Lite section 10.7:

[10.7] Should you use the this pointer
in the constructor?

[...snip...]

Here is something that never works:
the {body} of a constructor (or a
function called from the constructor)
cannot get down to a derived class by
calling a virtual member function that
is overridden in the derived class.
If
your goal was to get to the overridden
function in the derived class, you
won't get what you want. Note that you
won't get to the override in the
derived class independent of how you
call the virtual member function:
explicitly using the this pointer
(e.g., this->method()), implicitly
using the this pointer (e.g.,
method()), or even calling some other
function that calls the virtual member
function on your this object. The
bottom line is this: even if the
caller is constructing an object of a
derived class, during the constructor
of the base class, your object is not
yet of that derived class.
You have
been warned.

NOTE: Emphasis mine.

More details at the link

薄凉少年不暖心 2024-09-21 22:20:06

唯一可以执行此操作的情况是当某个内容派生自自行参数化的模板时:

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++ 编译器团队是否有效,但没有人确定它是否有效,因为模板构造取决于名称,如下所示:

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

这包括能够在构造期间从 base 调用派生 的非虚拟公共成员,因为它已经是 base 的一部分。对此有很大的限制。特别是,如果 doSomething() 依赖于 categories 的构造函数中构造的任何内容,则它将无法工作,因为 categories 尚未构造。

现在,这实际上是个好主意吗?不。

The only time you can do this is when something is derived from a template that is parameterised by itself:

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

Note that doSomething is public and not virtual.

We can static_cast to derived, because it's known that derived is the derived type.

Deriving something from a base parameterised by itself is a strange thing to be doing at the best of times. It's said that when the ATL team in microsoft used it they asked the C++ compiler team if it was valid and nobody was sure, though it is valid because template construction depends on names as follows:

First the template is available, but not used in a class. Then, the name derived available. Then it instantiates the layout of base<derived> — this requires knowledge of the member variables and virtual functions, as long as none of that depends upon knowledge of derived’s layout (pointers and references are fine) this will all go okay. Then it will create the layout of derived, and finally it will create derived’s member functions, which may include creating member functions for base<derived>. So as long as base<derived> doesn’t contain a derived member variable (base classes can never contain a member variable of a type derived from themselves) or a virtual function that requires knowledge of derived’s layout we can indeed do the dicey-looking piece of inheritance above.

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.

野味少女 2024-09-21 22:20:06

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

A simple design solution is to use aggregation instead of inheritance.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文