Делегирующие конструкторы и ссылочные параметры - PullRequest
3 голосов
/ 25 октября 2019

Я хотел бы реализовать несколько конструкторов для моего класса через перегрузку. Как я понимаю, способ сделать это идиоматически, следуя принципу DRY, заключается в использовании функции, называемой делегированием конструкторов. Я также видел мысли о том, чтобы везде использовать ссылочные параметры и избегать указателей любой ценой, потому что ссылки - это способ c ++ и т. Д.

Так вот, как я вижу, это можно реализовать с помощью указателей (что работает):

class B {};
class C {};

class A {
public:
    A();
    A(const B* b);
    A(const B* b, const C* c);
private:
    const B* b_;
    const C* c_;
};

// These ctors short and concise, delegating work to last ctor
A::A() : A(nullptr, nullptr) {}
A::A(const B* b) : A(b, nullptr) {}

// This ctor contains code that deals with b or c being nullptr
// Ideally I only modify code in this ctor (DRY)
A::A(const B* b, const C* c) : b_(b), c_(c) { 
   //code
}

Следующее, очевидно , не работает:

class B {};
class C {};

class A {
public:
    A();
    A(const B& b);
    A(const B& b, const C& c);
private:
    const B& b_;
    const C& c_;
};

A::A() : A(nullptr, nullptr) {}

A::A(const B& b) : A(b, nullptr) {}

A::A(const B& b, const C& c) : b_(b), c_(c) {
   //code
}

Поэтому вопрос заключается в том, как реализовать делегирование конструкторов, следующих семантике впример указателя, но со ссылкой в ​​качестве параметров конструктора.

(Полностью ли я здесь пропускаю точку? Может быть, даже пялиться на общую идею?)

Ответы [ 2 ]

1 голос
/ 25 октября 2019

Предполагая, что ваши члены 'A' являются ссылками, один из способов разрешить это будет иметь какое-то специальное "нулевое" значение для каждого из ваших классов:

class B {};
class C {};

class A
{
public:
    A();
    A(const B& b);
    A(const B& b, const C& c);
private:
    const B& b_;
    const C& c_;
    static const B null_b;
    static const C null_c;
};

A::A() : A(null_b, null_c) {}

A::A(const B& b) : A(b, null_c) {}

A::A(const B& b, const C& c) : b_(b), c_(c) {
}
1 голос
/ 25 октября 2019

Вы не можете передать nullptr на ссылку. Он существует именно для этой цели.

Указатель - это переменная, которая содержит адрес переменной. Ссылка - это переменная адреса, поэтому она не может ссылаться ни на что и не может быть переназначена.

Когда вы пишете

 A(const B& b)

, вы заключаете договор. Вы утверждаете: «Я хочу построить A с обязательным объектом B. B, являющийся нулевым, здесь не вариант».

Делегирование этому конструктору означает следование его контракту. Таким образом, с этим предположением ваша делегация отлично работает с:

struct B{};

struct A{
  A() : A(B{}){}  // Constructing a pre-defined B object

  A(const B& b) : _b{b}{}
  B _b;  
};


int main ()
{
  A a;
}

Живой код здесь

сказал, что если вы хотите выразить обнуляемый тип, вы можете использовать std::optional если C ++ 17 является опцией. Если у вас есть полиморфный объект, я бы предложил использовать умный указатель, чтобы лучше выразить владение и лучше контролировать свой код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...