C++ 链接成员函数使用 .chain().method() 与 ->chained(0->method()

标签 c++ this chaining method-chaining

问题的简短版本

我就是否使用 ./*this 与 ->/this 寻求建议, 即 C++ (*this).chained().methods() 与 this->chained()->methods()。

顺便说一句,目前我看到的大部分页面都推荐 [[C++ (*this).chained().methods()]].

我只是想知道,因为你做不到

My_Class object.chained().methods();

(顺便说一句,我没有测试第一部分中的示例。我在第二部分中提供了测试示例。)

你必须做

My_Class object;
object.chained().methods();

这是一个恼人的额外行

或者你可以做

 My_Class object = My_Class().object.chained().methods();

这需要一个值拷贝——如果构造函数有副作用是 Not Acceptable ,比如注册对象实例——就像许多 Knobs 库所做的那样

或者你可以做

 My_Class* object_ptr = *(new My_Class).object.chained().methods();

这有效,但需要烦人的 *(ptr)

或者你可以做

 My_Class* object_ptr = (new My_Class)->object.chained()->methods();

稍微好一点。

我想你可以做到

My_Class& object_ref(My_Class().chained().methods());

我不确定我是怎么想的。

顺便说一句,我在这里不需要调试帮助。
我一直在编写这样的代码 我提供示例只是为了清楚起见。

我正在寻求风格建议,因为有几种编码方式, 我使用了以相反方式执行此操作的不同库。

混合它们很丑陋:

  My_Object_with_Setters* object_ptr2 = &((new My_Object_with_Setters)->set_R1(1).set_P1(2)->set_R1(3))

 My_Object().method_returning_ptr()->method_returning_ref();

也许它并没有那么糟糕......但它肯定会令人困惑。

当我遇到使用混合 .chained()->methods() 的两个不同库的代码时 有时我希望能够拥有后缀寻址和取消引用运算符

My_Object* mptr = My_Object() .method_returning_ptr() -> method_returning_ref ->&

更完整的例子

设置函数

我最常将这个习语与 setter 函数一起使用

class My_Object_with_Setters {
public:
  static int count;
  int value;
public:
  My_Object_with_Setters() {
    ++count;
    value = 0;
  }
public:
  std::ostream& print_to_stream(std::ostream& ostr) const {
    ostr << "(" << this->count << "," << this->value << ")";
    return ostr;
  }
  friend std::ostream&
  operator<< (
    std::ostream& ostr,
    const My_Object_with_Setters& obj ) {
    return obj.print_to_stream(ostr);
  }

public:
  My_Object_with_Setters& set_R1(int val) {
    this->value = val;
    std::cout << "set_R1: " << *this << "\n";
    return *this;
  }
  My_Object_with_Setters& set_R2(int val) {
    this->value = val;
    std::cout << "set_R2: " << *this << "\n";
    return *this;
  }
public:
  My_Object_with_Setters* set_P1(int val) {
    this->value = val;
    std::cout << "set_P1: " << *this << "\n";
    return this;
  }
  My_Object_with_Setters* set_P2(int val) {
    this->value = val;
    std::cout << "set_P2: " << *this << "\n";
    return this;
  }
public:
  My_Object_with_Setters set_V1(int val) {
    this->value = val;
    std::cout << "set_V1: " << *this << "\n";
    My_Object_with_Setters retval;
    retval = *this;     // kluge to force new object
    return retval;
  }
  My_Object_with_Setters set_V2(int val) {
    this->value = val;
    std::cout << "set_V2: " << *this << "\n";
    My_Object_with_Setters retval;
    retval = *this;     // kluge to force new object
    return retval;
  }
};

int My_Object_with_Setters::count = 0;  // clas static, distinguishes instances

void test_My_Object_with_Setters()
{
  std::cout << "cascading ref, ref, copy, copy, ref, ref\n";
  My_Object_with_Setters object;
  object.set_R1(1).set_R2(2).set_V1(11).set_V2(12).set_R1(101).set_R2(102);

  std::cout << "cascading ptr, ptr, ptr, ptr\n";
  My_Object_with_Setters* object_ptr = (new My_Object_with_Setters)->set_P1(1)->set_P2(2)->set_P1(11)->set_P2(12);

  std::cout << "cascading &address-of, ptr, ptr\n";
  (&object)->set_P1(1)->set_P2(2);

  std::cout << "cascading new ptr ref ptr ref\n";
  My_Object_with_Setters* object_ptr2 = &(*(new My_Object_with_Setters)->set_R1(1).set_P1(2)).set_R1(3);

}

测试输出:

cascading ref, ref, copy, copy, ref, ref
set_R1: (1,1)
set_R2: (1,2)
set_V1: (1,11)
set_V2: (2,12)
set_R1: (3,101)
set_R2: (3,102)
cascading ptr, ptr, ptr, ptr
set_P1: (4,1)
set_P2: (4,2)
set_P1: (4,11)
set_P2: (4,12)
cascading &address-of, ptr, ptr
set_P1: (4,1)
set_P2: (4,2)
cascading new ptr ref ptr ref
set_R1: (5,1)
set_P1: (5,2)
set_R1: (5,3)

通用示例

class My_Object {
public:
  static int count;
public:
  My_Object() {
    ++count;
  }
public:
  My_Object& method1_returning_ref_to_current_object() {
    std::cout << count << ": method1_returning_ref_to_current_object\n";
    return *this;
  }
  My_Object& method2_returning_ref_to_current_object() {
    std::cout << count << ": method2_returning_ref_to_current_object\n";
    return *this;
  }
public:
  My_Object* method1_returning_ptr_to_current_object() {
    std::cout << count << ": method1_returning_ptr_to_current_object\n";
    return this;
  }
  My_Object* method2_returning_ptr_to_current_object() {
    std::cout << count << ": method2_returning_ptr_to_current_object\n";
    return this;
  }
public:
  My_Object method1_returning_value_copy_of_current_object() {
    std::cout << count << ": method1_returning_value_copy_of_current_object\n";
    My_Object retval;
    return retval;
  }
  My_Object method2_returning_value_copy_of_current_object() {
    std::cout << count << ": method2_returning_value_copy_of_current_object\n";
    My_Object retval;
    return *this;
  }
};

int My_Object::count = 0;   // clas static, distinguishes instances

void test_My_Object()
{
  std::cout << "cascading ref, ref, copy, copy, ref, ref\n";
  My_Object object;
  object
   .method1_returning_ref_to_current_object()
   .method2_returning_ref_to_current_object()
   .method1_returning_value_copy_of_current_object()
   .method2_returning_value_copy_of_current_object()
   .method1_returning_ref_to_current_object()
   .method2_returning_ref_to_current_object()
   ;

  std::cout << "cascading ptr, ptr, ptr, ptr\n";
  My_Object* object_ptr = new My_Object;
  object_ptr
   ->method1_returning_ptr_to_current_object()
   ->method2_returning_ptr_to_current_object()
   ->method1_returning_ptr_to_current_object()
   ->method2_returning_ptr_to_current_object()
   ;

  std::cout << "cascading &address-of, ptr, ptr\n";
  (&object)
   ->method1_returning_ptr_to_current_object()
   ->method2_returning_ptr_to_current_object()
   ;

  std::cout << "cascading new ptr ref ptr ref\n";
  My_Object* object_ptr2
   = (&(*(new My_Object)
    ->method1_returning_ptr_to_current_object())
    .method2_returning_ref_to_current_object())
   ;

}

测试输出

cascading ref, ref, copy, copy, ref, ref
1: method1_returning_ref_to_current_object
1: method2_returning_ref_to_current_object
1: method1_returning_value_copy_of_current_object
2: method2_returning_value_copy_of_current_object
3: method1_returning_ref_to_current_object
3: method2_returning_ref_to_current_object
cascading ptr, ptr, ptr, ptr
4: method1_returning_ptr_to_current_object
4: method2_returning_ptr_to_current_object
4: method1_returning_ptr_to_current_object
4: method2_returning_ptr_to_current_object
cascading &address-of, ptr, ptr
4: method1_returning_ptr_to_current_object
4: method2_returning_ptr_to_current_object
cascading new ptr ref ptr ref
5: method1_returning_ptr_to_current_object
5: method2_returning_ref_to_current_object

顺便说一句,我在这里不需要调试帮助。我提供示例只是为了清楚起见。

我正在寻求风格建议。

最佳答案

每个人都有自己的风格;正如您所说,只有当您开始混合它们时,它才会真正变得烦人。

就我个人而言,我只从函数返回一个可能为 0 的指针; this 永远不会为 0,所以我总是会返回 *this(即引用),因此与 . 链接。

为了它的值(value),我也非常努力地尝试让默认构造函数变得便宜,部分原因是在很多情况下,先默认构造然后赋值会很方便。

关于C++ 链接成员函数使用 .chain().method() 与 ->chained(0->method(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13964970/

相关文章:

c++ - C++ 中的 `this` 运算符?

c++ - 将共享指针还是原始指针传递给函数

java - this(<params>) 作为构造函数中的快捷方式?

java - 链接方法模式

c++ - 在 C++ 中作为参数传递时变量何时被复制?

c++ - Ofstream 比 cout 快? ||存储速度快于视觉输出

javascript - 适当使用Javascript的bind()

javascript - `this` 和 Javascript 回调中的范围

hadoop - map->map->reduce->reduce->最终输出

用于链接和释放的 C 矩阵函数设计