稍后在 C++ 中调用基类构造函数(不在初始值设定项列表中)

发布于 2024-09-25 08:46:56 字数 181 浏览 7 评论 0原文

我正在继承一个类,我想调用它的构造函数之一。但是,在调用它之前,我必须处理一些内容(不需要基类的任何内容)。有什么方法可以稍后调用它,而不是在初始化列表上调用它?我相信这可以在 Java 和 C# 中完成,但我不确定 C++ 是否可以。

我需要传递给构造函数的数据以后无法重新分配,因此我不能只调用默认构造函数并稍后对其进行初始化。

I'm inheriting a class and I would like to call one of its constructors. However, I have to process some stuff (that doesn't require anything of the base class) before calling it. Is there any way I can just call it later instead of calling it on the initializer list? I believe this can be done in Java and C# but I'm not sure about C++.

The data that I need to pass on the constructor can't be reassigned later, so I can't just call a default constructor and initialize it later.

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

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

发布评论

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

评论(6

灯角 2024-10-02 08:46:57

根据 @Konrad 的建议,另一种选择是使用静态方法来构造对象,例如:

class Derived {
public:
    Derived(int p1, int p2, int p3) : Base(p1, p2) { }

    static Derived* CreateDerived(int p3) { return new Derived(42, 314, p3); }
};

我发现这在从库扩展类并具有多个要覆盖的参数时很有用。
您甚至可以将构造函数设置为私有

Another option, based on the suggestion from @Konrad is to have a static method to construct the object, e.g.:

class Derived {
public:
    Derived(int p1, int p2, int p3) : Base(p1, p2) { }

    static Derived* CreateDerived(int p3) { return new Derived(42, 314, p3); }
};

Ive found this useful when extending a class from a library and having multiple parameters to override.
You can even make the constructor private

云柯 2024-10-02 08:46:57
struct base{
   base(int x){}
};

struct derived : base{
   derived(int x) : base(x){}
};

这就是 C++ 中从派生类的初始化列表调用基类构造函数的方式。

struct base{
   base(int x){}
};

struct derived : base{
   derived(int x) : base(x){}
};

This is how base class constructors are invoked in C++ from the initialization list of derived class.

十二 2024-10-02 08:46:56

有什么方法可以让我稍后调用它,而不是在初始值设定项列表上调用它?

不,你不能。基类构造函数必须在初始化列表中调用,并且必须首先调用。

事实上,如果您省略它,编译器只会隐式添加调用。

我相信这可以在 Java 和 C# 中完成,但我不确定 C++。

C# 和 Java 都不允许这样做。

然而,您可以做的是调用一个方法作为基类构造函数调用的参数。然后在构造函数之前处理:

class Derived {
public:
    Derived() : Base(some_function()) { }

private:
    static int some_function() { return 42; }
};

Is there any way I can just call it later instead of calling it on the initializer list?

No, you cannot. The base class constructor must be called in the initializer list, and it must be called first.

In fact, if you omit it there, the compiler will just add the call implicitly.

I believe this can be done in Java and C# but I'm not sure about C++.

Neither C# nor Java allow this either.

What you can do, however, is call a method as an argument of the base class constructor call. This is then processed before the constructor:

class Derived {
public:
    Derived() : Base(some_function()) { }

private:
    static int some_function() { return 42; }
};
北方的韩爷 2024-10-02 08:46:56

正如几个人回答的那样,您不能延迟基类构造函数的调用,但是 K​​onrad 给出了一个很好的答案,很可能会解决您的问题。但是,这确实有其缺点(例如,当您需要使用其计算共享中间结果的值来初始化多个函数时),因此为了完整起见,这是解决固定初始化顺序问题的另一种方法,通过使用它。

给定固定的初始化顺序,如果您可以控制派生类(否则您将如何摆弄其中一个构造函数?),您可以潜入一个私有基,以便它将在另一个基类之前初始化基,然后可以使用私有基已计算的值进行初始化:

class my_dirty_little_secret {
  // friend class the_class;
public: 
  my_dirty_little_secret(const std::string& str)
  {
    // however that calculates x, y, and z from str I wouldn't know
  }
  int x;
  std::string y;
  float z;
};

class the_class : private my_dirty_little_secret // must be first, see ctor
                , public the_other_base_class {
  public:
    the_class(const std::string str)
      : my_dirty_little_secret(str)
      , the_other_base_class(x, y, z)
    {
    }
  // ...
};

my_dirty_little_secret 类是一个私有基,因此 the_class 的用户无法使用它,它的所有内容都是也是私有的,具有明确的友谊,仅授予 the_class 访问权限。但是,由于它在基类列表中首先列出,因此它将在 the_other_base_class 之前可靠地构造,因此无论它计算什么都可以用来初始化它。
基类列表中的一个很好的注释有望防止其他人通过重构破坏事物。

As was said by several people answering, you cannot delay the invocation of a base class constructor, but Konrad has given a good answer that might well solve your problem. However, this does have its drawbacks (for example, when you need to initialize several functions with values whose calculations share intermediate results), so just to be complete, here's another way of solving the problem of fixed initialization order, by using it.

Given the fixed order of initialization, if you have control over the derived class (and how else would you come to fiddle with one of its ctors?), you can sneak in a private base so that it is going to be initialized before the other base, which can then be initialized with the private base's already calculated values:

class my_dirty_little_secret {
  // friend class the_class;
public: 
  my_dirty_little_secret(const std::string& str)
  {
    // however that calculates x, y, and z from str I wouldn't know
  }
  int x;
  std::string y;
  float z;
};

class the_class : private my_dirty_little_secret // must be first, see ctor
                , public the_other_base_class {
  public:
    the_class(const std::string str)
      : my_dirty_little_secret(str)
      , the_other_base_class(x, y, z)
    {
    }
  // ...
};

The my_dirty_little_secret class is a private base so that users of the_class cannot use it, all of its stuff is private, too, with explicit friendship granting only the_class access to it. However, since it's listed first in the base class list, it will reliably be constructed before the_other_base_class, so whatever it calculates can be used to initialize that.
A nice comment at the base class list hopefully prevents from others breaking things by refactoring.

小霸王臭丫头 2024-10-02 08:46:56

恕我直言,我认为不可能以您提到的方式推迟调用基类构造函数。

IMHO I dont think it is possible to defer calling the base class constructor in the way that you mentioned.

甜宝宝 2024-10-02 08:46:56

哇,我们都曾经年轻过。这个答案不会起作用,所以不要使用它。出于历史目的而留下的内容。

如果您可以完全控制基类,我建议添加一个受保护的方法来进行类初始化,使其成为虚拟的,并在调用其基类之前将派生类实现细节放入其中:

class Base
{
public:
    Base()
    {
        Initialize();
    }
protected:
    virtual void Initialize()
    {
        //do initialization;
    }
};

class Derived : Base
{
public:

    Derived() : Base()
    {
    }
protected:
    virtual void Initialize()
    {
        //Do my initialization
        //call base
        Base::Initialize();
    }
};

Wow, we were all young once. This answer won't work, so don't use it. Content left for historical purposes.

If you have full control over the base class, I'd recommend adding a protected method to do the class initialization, make it virtual, and put the your derived class implementation details in it before it calls its base:

class Base
{
public:
    Base()
    {
        Initialize();
    }
protected:
    virtual void Initialize()
    {
        //do initialization;
    }
};

class Derived : Base
{
public:

    Derived() : Base()
    {
    }
protected:
    virtual void Initialize()
    {
        //Do my initialization
        //call base
        Base::Initialize();
    }
};
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文