c++ - 成员如何知道它是在哪个类实例中构造的?

标签 c++ constructor


    class C {
    public
      T x;
    };

是否有一种优雅的方式让 x 的构造函数隐式知道它正在构造哪个 C 实例?


我已经用一些肮脏的不优雅的机器实现了这种行为。我的 sqlite3 包装器需要这个。我不喜欢我见过的所有包装器,它们的 API IMO 丑陋且不方便。我想要这样的东西:


    class TestRecordset: public Recordset {
    public:
      // The order of fields declarations specifies column index of the field.
      // There is TestRecordset* pointer inside Field class, 
      // but it goes here indirectly  so I don't have to 
      // re-type all the fields in the constructor initializer list.
      Field<__int64> field1;
      Field<wstring> field2;
      Field<double> field3;

      // have TestRecordset* pointer too so only name of parameter is specified
      // in TestRecordset constructor
      Param<wstring> param;

      virtual string get_sql() {
        return "SELECT 1, '1', NULL FROM test_table WHERE param=:PARAM";
      }

      // try & unlock are there because of my dirty tricks.
      // I want to get rid of them.

      TestRecordset(wstring param_value)
      try : Recordset(open_database(L"test.db")), param("PARAM") {
        param = param_value;
       // I LOVE RAII but i cant use it here. 
       // Lock is set in Recordset constructor, 
       // not in TestRecordset constructor.
        unlock(this);
        fetch();
      } catch(...) {
        unlock(this);
        throw;
      }
    };
<code></code>
<code> <p>I want to clarify the fact - it is a part of the <i>working</i> code. You <i>can</i> do this in C++. I just want to do it in a more nice way. </p><hr/> I've found a way to get rid of unlock and try block. I've remembered there is such a thing as thread local storage. Now I can write constructor as simple as that:<p></p> </code><pre><code> TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param("PARAM") { param = param_value; fetch(); } </code></pre> <p></p><hr/> to dribeas: My objective is to avoid redundant and tedious typing. Without some tricks behind the scene I will have to type for each Field and Param:<p></p>
TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param(this, "PARAM"),
   field1(this, 0), field2(this, 1), field3(this, 2) { ... }

它是多余的、丑陋的和不方便的。例如,如果我必须在 SELECT 的中间我将不得不重写所有的列号。 关于您帖子的一些注释:

  1. 字段和参数 由它们的默认构造函数初始化。
  2. 构造函数中初始化器的顺序无关紧要。字段总是按照声明的顺序进行初始化。我已经使用这个事实来追踪字段的列索引
  3. 首先构造基类。因此,当构造字段时,记录集中的内部字段列表已准备好由 Filed 默认构造函数使用。
  4. 我不能在这里使用 RAII。我需要在 Recorset 构造函数中获取锁并在 TestRecordset 构造函数中强制释放它在构造所有字段之后

最佳答案

没有。对象不应该为了工作而需要知道它们从哪里被使用。就 x 而言,它是 T 的一个实例。仅此而已。根据它是类 C 的成员、类 D 的成员、自动的、临时的等,它的行为没有区别。

此外,即使 T 构造函数确实知道 C 的实例,C 的实例也将是不完整的,因为它当然还没有完成构造,因为它的成员还没有被构造。 C++ 为您提供了大量搬起石头砸自己脚的机会,但在另一个类的构造函数中为您提供对不完整对象的引用并不是其中之一。

我唯一能想到的近似您的代码示例的方法是做类似的事情

#define INIT_FIELDS field1(this), field2(this), field3(this)

紧跟在字段列表之后,然后在初始化列表中使用 INIT_FIELDS 并 #undef 它。它仍然是重复的,但至少它都在一个地方。然而,这可能会让您的同事感到惊讶。

另一种确保您不会忘记字段的方法是从 Field 中删除零参数构造函数。同样,您仍然必须进行输入,但至少如果您忘记了某些内容,编译器会捕捉到它。我认为,初始化列表的非 DRY 性质是 C++ 必须忍受的。

关于c++ - 成员如何知道它是在哪个类实例中构造的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/338271/

相关文章:

c++ - SLD2 - 绘制一个纹理的多个实例的最快方法

c++ - 如何在 gtest 中通过 CURL 测试 HTTPS 请求(SSL)?

c++ - 用字符串文字构造一个对象

c++ - 在 C++ 中检查数字是否为整数

C++访问 vector 的一定范围的索引

c++ - 在 C++ 项目中留下未使用的类有什么缺点?

javascript - 简单的 JavaScript 对象构造函数

java - 在 Scala 中,如何子类化具有多个构造函数的 Java 类?

c++ - C++ 对象成员数组的默认初始化?

java - 为什么一个类的子类类必须是静态的才能在类的构造函数中初始化子类?