this — функции цепочки-члена C ++ с использованием .chain (). method () и -> chained (0-> gt; method ()

Краткая версия вопроса

Я обращаюсь за советом относительно того, следует ли использовать ./*this -> / this,
то есть C ++ (* this) .chained (). Methods () против this-> chained () -> Methods ().

Кстати, на данный момент большинство страниц, которые я видел, рекомендуют
[[C ++ (* this) .chained (). Methods ()]].

Мне было просто интересно, потому что вы не можете сделать

My_Class object.chained (). Method ();

(Кстати, я не проверял примеры в этом первом разделе. Я предоставляю проверенные примеры во втором разделе.)

Ты должен сделать

Объект My_Class;
object.chained () методы ().

что раздражает дополнительная линия

Или вы можете сделать

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

который требует копирования значения — не приемлемо, если конструктор имеет побочные эффекты, такие как регистрация экземпляра объекта — как это делают многие библиотеки Knobs

Или вы можете сделать

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

который работает, но требует, чтобы это раздражало * (ptr)

Или вы можете сделать

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

что немного лучше.

Я полагаю, вы можете сделать

Мои занятия& object_ref (.. my_class () цепь () методы ());

и я не уверен, что я думаю об этом.

Кстати, мне не нужна помощь в отладке здесь.
Я постоянно пишу такие вещи
Я приведу примеры только для ясности.

Я ищу совет по стилю, потому что есть несколько способов его кодирования,
и я использовал разные библиотеки, которые делают это противоположными способами.

И смешивать их безобразно

  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 () -> методов ()
Иногда я хочу иметь возможность иметь постфиксные операторы адреса и разыменования

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

Более полные примеры

Я чаще всего использую эту идиому с функциями сеттера

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

Кстати, мне не нужна помощь в отладке здесь. Я приведу примеры только для ясности.

Я ищу совет стиля.

4

Решение

У каждого свой стиль; как вы говорите, это только раздражает, когда вы начинаете смешивать их.

Лично я возвращаю указатель из функции, только если он может быть 0; this никогда не равен 0, поэтому я бы всегда вернулся *this (т.е. ссылка) и, таким образом, цепь с .,

Что бы это ни стоило, я также очень стараюсь сделать конструктор по умолчанию дешевым, отчасти потому, что существует очень много случаев, когда оказывается удобным сначала создать конструкцию по умолчанию, а затем присвоить.

6

Другие решения

Лучший ответ, который я могу дать — «будь последовательным». Если остальная часть вашего кода использует this->, используйте это. Если он использует (*this)., используйте это.

Поскольку разница заключается только в синтаксическом сахаре, ваше лучшее руководство — то, что делает другой код, который вы используете. Большинство людей, которых я знаю, предпочли бы -> синтаксис, но если вы интегрируете в существующие библиотеки, вы можете пропустить его.

Лично я бы использовал внеплановый метод инициализации. Он читает для меня самое чистое: одна строка создает объект в стеке, другие вызывают методы по мере необходимости. Если вам нужны только методы, и они не зависят от реального объекта, я бы сделал их статическими и пропустил бы создание объекта все вместе.

2

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector