psb
psb

Reputation: 392

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?)

Upvotes: 4

Views: 717

Answers (2)

Moia
Moia

Reputation: 2354

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.

Upvotes: 2

Alan Birtles
Alan Birtles

Reputation: 36399

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) {
}

Upvotes: 1

Related Questions