c++ - Calling parameterized constructor only to update one member variable - Stack Overflow

admin2025-04-08  0

I have a class with a default constructor which initializes many member variables via initializer lists.

I wish to have a parametrized constructor which only updates one of the member variables. A simple example is below, with name being the only variable that I would like to initialize via the default constructor.

Does it make sense to repeat the initializer list the same as for the default constructor here? Or can I call the default constructor from the parameterized constructor first?

What is the most efficient way to do this?

#include <iostream>
#include<iostream>
#include<fstream>

using namespace std;

class MyClass
{
    public:
        MyClass() : name("John"),
                    age(20),
                    distance(10)
                    // Many more default initializers
        {

        }

        MyClass(string name)
        {
            // How to only initialize name with the parameter passed, while everything else still gets the default value like in the default constructor. 

        }

        ~MyClass()
        {

        }

    private:
        string name;
        int age;
        int distance;
        // Many more 
};

I have a class with a default constructor which initializes many member variables via initializer lists.

I wish to have a parametrized constructor which only updates one of the member variables. A simple example is below, with name being the only variable that I would like to initialize via the default constructor.

Does it make sense to repeat the initializer list the same as for the default constructor here? Or can I call the default constructor from the parameterized constructor first?

What is the most efficient way to do this?

#include <iostream>
#include<iostream>
#include<fstream>

using namespace std;

class MyClass
{
    public:
        MyClass() : name("John"),
                    age(20),
                    distance(10)
                    // Many more default initializers
        {

        }

        MyClass(string name)
        {
            // How to only initialize name with the parameter passed, while everything else still gets the default value like in the default constructor. 

        }

        ~MyClass()
        {

        }

    private:
        string name;
        int age;
        int distance;
        // Many more 
};
Share Improve this question edited Mar 26 at 22:14 Remy Lebeau 601k36 gold badges507 silver badges851 bronze badges asked Mar 26 at 21:50 Engineer999Engineer999 4,0478 gold badges42 silver badges95 bronze badges 5
  • "// How to only initialize name" - this will be a bug. The values must not be left uninitialized. – 3CxEZiVlQ Commented Mar 26 at 21:52
  • @3CxEZiVlQ No, I mean only initialize name with a parameter from the paramaterized constructor. Everything else still should get the default value as per the default constructor. – Engineer999 Commented Mar 26 at 21:56
  • What you want to get in the constructor initializer list is impossible - we can't re-initialize member variables after the default constructor. – 3CxEZiVlQ Commented Mar 26 at 21:58
  • Read about Delegating constructor. – Jesper Juhl Commented Mar 27 at 0:10
  • Builder pattern might interest you too. – Jarod42 Commented Mar 27 at 8:57
Add a comment  | 

3 Answers 3

Reset to default 6
// How to only initialize name`

This will be a bug. Other values must not be left uninitialized.

Perhaps, you wanted

#include <string>
#include <utility>

class MyClass {
 public:
  MyClass() : MyClass("John") {} // delegate to the ctor below

  explicit MyClass(std::string name) : name(std::move(name)), age(20), distance(10) {}

  ~MyClass() = default;

 private:
  std::string name;
  int age;
  int distance;
};

Or

#include <string>
#include <utility>

class MyClass {
 public:
  MyClass() = default;

  explicit MyClass(std::string name) : name(std::move(name)){}

  ~MyClass() = default;

 private:
  std::string name = "John";
  int age = 20;
  int distance = 10;
};

There are different ways to accomplish this:

  • Define multiple constructors

#include<iostream>
#include<fstream>

using namespace std;

class MyClass
{
    public:
        MyClass() : MyClass("John", 20, 10)
        {

        }

        MyClass(string name): MyClass(name, 20, 10)
        {

        }

        ~MyClass()
        {

        }

        MyClass(std::string pName, int pAge, int pDistance):
            name(pName),
            age(pAge),
            distance(pDistance)
            {}

    private:
        string name;
        int age;
        int distance;
        // Many more 
}; 
  • Initialize private members

    #include<iostream>
    #include<fstream>
    
    using namespace std;
    
    class MyClass
    {
        public:
            MyClass()
            {
                // using the default values 
            }
    
            MyClass(string pName): name(name)
            {
                // update the value of name and keep other set to default
            }
    
            ~MyClass()
            {
    
            }
    
            MyClass(std::string pName, int pAge, int pDistance):
                name(pName),
                age(pAge),
                distance(pDistance)
                {
                    // if needed, you can have another constructor to change the default values
                }
    
        private:
            string name = std::string("default name");
            int age = 0;
            int distance = 0;
            // Many more 
    };
    

The optimum solution depends on your requirements/usage.

For example, if you go for the second option, any change in the default values will trigger a rebuild on all files including the class definition.

My preferred method is aggregate builder pattern:

class MyClass {
public:
    struct my_init{
    //Aggregate builder class
        std::string name = "John";
        int age = 20;
        int distance = 10;
    };

    MyClass() = default;

    explicit MyClass(my_init val)
    : my{std::move(val)} {};

    ~MyClass() = default;

private:
    my_init val;
};

MyClass my_obj0;

//double brackets is the cost:
MyClass my_obj1 {{ .distance=50 }};

This pattern uses named parameters through designated initializer list of aggregate classes. If MyClass members have differing access specifiers, then a little more complexity is introduced into the class:

class MyClass {
public:
    //Aggregate builder class:
    struct my_init;//same as above

    MyClass()
    //delegating constructor call:
    : MyClass{my_init{}} {};

    explicit MyClass(my_init val)
    : name{std::move(val).name}
    , age{std::move(val).age}
    , dist{std::move(val).distance}
    {/*ctor*/};

    ~MyClass() = default;

private:
    std::string name;
protected:
    int age;
    int dist;
};

This is still much simpler than JAVA style builder pattern.

转载请注明原文地址:http://conceptsofalgorithm.com/Algorithm/1744124265a232389.html

最新回复(0)