Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delegating constructors and reference parameters

I would like to implement several constructors for my class via overloading. As I understand the way to do this idiomatically, following the DRY principle, is using a feature called delegating constructors. I also have seen thoughts about using reference parameters everywhere and avoiding pointers at all cost because references is a c++ way etc.

So here is how I see this could be implemented with pointers (which works):

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
}

The following, obviously, doesn't work:

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
}

So the question is how to implement delegating constructors following semantics in a pointer example but with reference as constructor's parameters.

(Do I totally miss the point here somewhere? Maybe even staring with the overall idea?)

like image 721
psb Avatar asked Oct 21 '25 04:10

psb


2 Answers

You cannot pass nullptr to a reference. It exists precisely with this purpose.

A pointer is a variable which contains an address to a variable. A reference is the address variable, so it can't refer to nothing and can't be reassigned.

When you write

 A(const B& b)

you are making a contract. you are stating: "I want to construct A with a mandatory B object. B being null is not an option here."

Delegating to this constructor means following its contract. So with this assumption your delegation works fine with:

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;
}

Live code here

said that, if you want to express a nullable type you can use std::optional if C++17 is an option. If you have polymorphic object I'd suggest to use smart pointer to express ownership better and have more control of your code.

like image 73
Moia Avatar answered Oct 22 '25 17:10

Moia


Assuming your members of 'A' are references, one way to allow this would be to have some special "null" value for each of your classes:

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) {
}
like image 20
Alan Birtles Avatar answered Oct 22 '25 19:10

Alan Birtles



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!