成员如何知道它构造在哪个类实例中?

Ser*_*kov 0 c++ constructor


    class C {
    public
      T x;
    };
Run Code Online (Sandbox Code Playgroud)

是否有一种优雅的方式让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;
      }
    };

我想澄清一下这个事实 - 它是工作代码的一部分.你可以用C++做到这一点.我只想以更好的方式做到这一点.


我找到了摆脱解锁和尝试阻止的方法.我记得有线程本地存储这样的东西.现在我可以编写简单的构造函数:

  TestRecordset(wstring param_value): 
    Recordset(open_database(L"test.db")), param("PARAM") {
        param = param_value;
        fetch();
   }
Run Code Online (Sandbox Code Playgroud)


对于dribeas:我的目标是避免多余和繁琐的打字.如果没有一些技巧,我将不得不为每个Field和Param键入:

TestRecordset(wstring param_value): Recordset(open_database(L"test.db")), param(this, "PARAM"),
   field1(this, 0), field2(this, 1), field3(this, 2) { ... }
Run Code Online (Sandbox Code Playgroud)

这是多余,丑陋和不方便的.例如,如果我必须在SELECT中间添加新字段,我将不得不重写所有列号.您帖子上的一些注意事项:

  1. 字段,而params 通过其默认的构造函数初始化.
  2. 构造函数中的初始化程序顺序无关紧要.字段始终按其声明的顺序初始化.我用这个事实来追踪字段的列索引
  3. 首先构造基类.因此,当构造Fields时,Recordset中的内部字段列表已准备好由Filed默认构造函数使用.
  4. 我不能在这里使用RAII.我需要在Recorset构造函数中获取锁,并在构造所有Fields之后在TestRecordset构造函数中释放它.

Ste*_*sop 8

不应该.对象不应该知道它们在哪里被使用才能工作.就x而言,它是T的一个实例.就是这样.根据它是C类的成员,D类的成员,自动,临时等,它的行为不同.

此外,即使T构造函数确实知道C的实例,C的实例也是不完整的,因为它当然还没有完成构造,因为它的成员还没有被构造.C++为你提供了很多机会射击自己,但是在另一个类的构造函数中提供一个不完整对象的引用并不是其中之一.

我能想到的唯一能够近似你的代码示例的是做类似的事情

#define INIT_FIELDS field1(this), field2(this), field3(this)
Run Code Online (Sandbox Code Playgroud)

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

另一种确保不忘记字段的方法是从Field中删除零参数构造函数.同样,您仍然需要进行输入,但至少如果您忘记了编译器将捕获它的内容.我认为,初始化程序列表的非DRY特性是C++必须要使用的东西.