如何调用未完全构造的对象的函数?

发布于 2024-12-04 12:35:51 字数 970 浏览 0 评论 0原文

使用构造函数创建一个对象,并调用正在构造的对象的函数:

class A
{
  public:
        A()
        {
        this->show();
        }   

        void show()
        {
        cout<<"show called!";
        }
};

现在我在 main() 中创建对象,如下所示:

int main()
{
    A a;
    int xy;
    cin>>xy;
    return 0;
}

我的疑问是,当我使用构造函数创建对象时那么当对象没有完全构造时我如何能够调用对象函数呢?

虚拟函数调用:

class A
{
  public:
        A()
        {

        }   

       virtual void show()
        {
        cout<<"show called!";
        }
};
class B:public A
{
      public: 
              B()
              {
                    A *a=this;
                    a->show();

                    }
             void show()
             {
                  cout<<"derived show";
                  }

      };


int main()
{
    A a;
    B b;
    int xy;
    cin>>xy;
    return 0;
}

输出正常工作:派生显示

creating an object using a constructor and along with that calling functions of object which is being constructed:

class A
{
  public:
        A()
        {
        this->show();
        }   

        void show()
        {
        cout<<"show called!";
        }
};

and now i m creating object in main() as below:

int main()
{
    A a;
    int xy;
    cin>>xy;
    return 0;
}

my doubt is that when i am creating an object using constructor then how i am able to call object function while object is not fully constructed?

virtual function calls:

class A
{
  public:
        A()
        {

        }   

       virtual void show()
        {
        cout<<"show called!";
        }
};
class B:public A
{
      public: 
              B()
              {
                    A *a=this;
                    a->show();

                    }
             void show()
             {
                  cout<<"derived show";
                  }

      };


int main()
{
    A a;
    B b;
    int xy;
    cin>>xy;
    return 0;
}

working fine with output: derived show

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

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

发布评论

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

评论(6

同尘 2024-12-11 12:35:51

可以调用虚函数和非静态成员函数:

请参阅 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf

可以调用4个成员函数,包括虚函数(10.3)
在建造或销毁期间(12.6.2)。

但是,在构造函数中使用虚函数时存在一些限制。有点拗口:

当虚拟函数被直接或间接调用时
构造函数(包括 mem-initializer 或
非静态数据成员的大括号或等于初始化器)或来自
析构函数,调用所适用的对象是该对象
在构造或销毁时,调用的函数是
在构造函数或析构函数自己的类或其之一中定义
基数,但不是在派生自该基数的类中覆盖它的函数
构造函数或析构函数的类,或在其中之一重写它
最底层派生对象的其他基类 (1.8)。

我将上面的段落解释为调用的虚函数不会出现在任何派生类中。这是有道理的,因为此时在执行阶段,派生类中的任何构造函数都不会开始执行。

此外,第 1 部分还规定了非静态成员的使用应在构造开始后进行。在您的示例中,成员在构造开始后被调用,因此您没有违反第 1 部分:

1 对于具有非平凡构造函数的对象,引用任何
构造函数之前对象的非静态成员或基类
开始执行会导致未定义的行为。

It's fine to call virtual functions and non-static member functions:

See section 12.7 of http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf:

4 Member functions, including virtual functions (10.3), can be called
during construction or destruction (12.6.2).

However when using virtual functions in a constructor there are some restrictions. It's a bit of a mouthful:

When a virtual function is called directly or indirectly from a
constructor (including the mem-initializer or
brace-or-equal-initializer for a non-static data member) or from a
destructor, and the object to which the call applies is the object
under construction or destruction, the function called is the one
defined in the constructor or destructor’s own class or in one of its
bases, but not a function overriding it in a class derived from the
constructor or destructor’s class, or overriding it in one of the
other base classes of the most derived object (1.8).

I interpret the above paragraph as saying the virtual functions called will not be in any derived class. This makes sense because at this point in the execution phase any constructor in a derived class will not have begun execution.

Additionally part 1 places a restriction that use of non-static members should occur after the construction begins. In your example the members are being invoked after the construction begins, so you're not violating part 1:

1 For an object with a non-trivial constructor, referring to any
non-static member or base class of the object before the constructor
begins execution results in undefined behavior.

紫南 2024-12-11 12:35:51

这段代码是完全合法的。您可以调用方法
在类构造函数中。

所有常量(来自初始化列表)都已初始化,并且所有基类构造函数都已调用。

但是,您不应在构造函数中调用虚拟方法。请参阅 Scott Meyers 对此限制的解释。

This code is completely legal. You can call methods
in the class constructor.

All constants (from the initialization list) are already initialized and all base class constructors are called.

However, You should not call virtual methods in the constructor. See Scott Meyers explanation for this restriction.

∞觅青森が 2024-12-11 12:35:51

需要考虑的是,调用 show() 时对象的哪些部分被构造?

由于您从构造函数体内(而不是例如构造函数的初始值设定项列表中)调用 show(),因此您可以放心,A 对象的所有成员变量都已被构造(因为这发生在执行构造函数体之前)。

如果 show() 是一个虚拟方法,并且 A::A() 是从 A 的子类的构造函数中调用的,那么可能会让您陷入困境。在这种情况下,您可能希望 show() 调用 B:: show() ,但这不会发生,因为 B 的 vtable 尚未设置(您最终会调用 A::show() ,或者如果 A::show() 是纯粹的,则程序崩溃-虚拟方法)

The thing to think about is, which parts of the object are constructed at the time when you call show()?

Since you call show() from within your constructor's body (and not e.g. from within the constructor's initializer list) you can rest assured that all of the A object's member variables have already been constructed (since that happens before the constructor body is executed).

What might trip you up would be if show() was a virtual method, and A::A() was being called from the constructor of a subclass of A. In that case, you might want show() to call B::show(), but that won't happen because the vtable for B hasn't been set up yet (you would end up calling A::show() instead, or crashing the program if A::show() was a pure-virtual method)

橘味果▽酱 2024-12-11 12:35:51

您正在部分构造的对象中调用函数,如果此类函数处理类成员等,则可能会导致错误的行为。我不确定它是否会调用未定义的行为,但我认为这不是一个好的做法。而继承和虚函数的情况会变得更糟!

在您的示例中,可以将 show 声明为静态,并且调用它不会有任何风险。

You are calling a function in an partially constructed object, which may result in erroneous behavior if such function deals with class members and such. I am not sure whether its invoking undefined behaviour or not, but I don't think its a good practice. And the situation gets worse with inheritance and virtual functions!

In your example, show could be declared static and there will be no risk in calling it.

丢了幸福的猪 2024-12-11 12:35:51

将类视为两个独立的部分:包含字段(变量)的对象和方法(函数)。给定类的方法独立于任何特定实例而存在,因此可以由有效实例随时调用它,甚至在构造过程中也是如此。

这些字段是在对象实例化时、构造函数运行之前“创建”的。但是,它们没有设置任何值。因此,如果您的构造函数在字段初始化为合理值之前调用任何方法,那么您将遇到一些未定义的行为。

只要有可能,如果必须在构造函数内调用方法,请确保将尽可能多的字段初始化为合理的值。

Consider a class as 2 separate parts: The object containing fields (variables) and the methods (functions). The methods of a given class exist independent of any particular instance, so it can be called at any time by a valid instance, even mid-construction.

The fields are "created" when the object is instantiated, before the constructor is run. However, they have no values set to them. So, if your constructor calls any methods BEFORE the fields are initialised to sensible values, then you're going to experience some undefined behaviour.

Whenever possible, if you must call a method inside a constructor, be sure to initialise as many fields as possible to sensible values.

无言温柔 2024-12-11 12:35:51

我的疑问是,当我使用构造函数创建对象时,我如何在对象未完全构造时调用对象函数?

只要您在应该初始化的位置(初始化列表)进行初始化,您的示例中发生的情况就很好。您正在对已初始化成员的对象使用静态分派(具体来说,A 没有要初始化的此类变量)。

那么什么是无效的呢?

  • 没有正确初始化您的成员,或者在真正初始化之前使用它们。支持初始化列表而不使用 this
  • 在构造函数主体(或初始值设定项)中使用动态调度。您的对象尚未完全构建。
  • 不同寻常的是,您还可以尝试从构造函数将其类型转换为子类。

my doubt is that when i am creating an object using constructor then how i am able to call object function while object is not fully constructed?

what happens in your example is fine, as long as you initialize where you are supposed to (the initialization list). you are using static dispatch on an object which has initialized members (specifically, A has no such variables to initialize).

what then is invalid?

  • not initializing your members correctly, or using them before they are really initialized. favor the initialization list without using this.
  • using dynamic dispatch from within your constructor's body (or initializer). your object is not fully constructed.
  • unusually, you could also attempt to typecast it to a subclass from the constructor.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文