154

Is it really not possible to create multiple constructors for a class in dart?

in my Player Class, If I have this constructor

Player(String name, int color) {
    this._color = color;
    this._name = name;
}

Then I try to add this constructor:

Player(Player another) {
    this._color = another.getColor();
    this._name = another.getName();
}

I get the following error:

The default constructor is already defined.

I'm not looking for a workaround by creating one Constructor with a bunch of non required arguments.

Is there a nice way to solve this?

Tom Porat
  • 1,562
  • 2
  • 7
  • 7
  • 1
    As an unrelated comment, you should probably be using getters for `color` and `name`, not `getColor()` and `getName()` methods. If the values never change, you can use a single public field like `class Player { final String name; final int color; Player(this.name, this.color); }`. – lrn Apr 06 '18 at 11:30
  • I'm new to dart and not yet used to these kind of standards, but thanks , I will give it a try. – Tom Porat Apr 06 '18 at 21:56

11 Answers11

266

You can only have one unnamed constructor, but you can have any number of additional named constructors

class Player {
  Player(String name, int color) {
    this._color = color;
    this._name = name;
  }

  Player.fromPlayer(Player another) {
    this._color = another.getColor();
    this._name = another.getName();
  }  
}

new Player.fromPlayer(playerOne);

This constructor

  Player(String name, int color) {
    this._color = color;
    this._name = name;
  }

can be simplified to

  Player(this._name, this._color);

Named constructors can also be private by starting the name with _

class Player {
  Player._(this._name, this._color);

  Player._foo();
}

Constructors with final fields initializer list are necessary:

class Player {
  final String name;
  final String color;

  Player(this.name, this.color);

  Player.fromPlayer(Player another) :
    color = another.color,
    name = another.name;
}
Quwaysim
  • 351
  • 3
  • 11
Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
12

If your class uses final parameters the accepted answer will not work. This does:

class Player {
  final String name;
  final String color;

  Player(this.name, this.color);

  Player.fromPlayer(Player another) :
    color = another.color,
    name = another.name;
}
Quentin
  • 758
  • 9
  • 11
5

If you already used a constructor with params in the project and now you figured out that you need some no params default constructor you can add an empty constructor.

class User{
String name;

   User({this.name}); //This you already had before
   User.empty(); //Add this later 
}
Moti Bartov
  • 3,454
  • 33
  • 42
3

Try the below code on DartPad

class MyClass {
  //These two are private attributes
  int _age;
  String _name;

  //This is a public attribute
  String defaultName = "My Default Name!";

  //Default constructor
  MyClass() {
    _age = 0;
    _name = "Anonymous";
  }

  MyClass.copyContructor(MyClass fromMyClass) {
    this._age = fromMyClass._age;
    this._name = fromMyClass._name;
  }

  MyClass.overloadedContructor(String name, int age) {
    this._age = age;
    this._name = name;
  }

  MyClass.overloadedContructorNamedArguemnts({String name, int age}) {
    this._age = age;
    this._name = name;
  }

  //Overriding the toString() method
  String toString() {
    String retVal = "Name:: " + _name + " | " + "Age:: " + _age.toString();
    return retVal;
  }
}

//The execution starts from here..
void main() {
  MyClass myClass1 = new MyClass();

  //Cannot access oprivate attributes
  //print(myClass1.name);
  //print(myClass1.age);

  //Can access the public attribute
  print("Default Name:: " + myClass1.defaultName);

  print(myClass1.toString());

  MyClass myClass2 = new MyClass.copyContructor(myClass1);

  print(myClass2.toString());

  MyClass myClass3 = new MyClass.overloadedContructor("Amit", 42);

  print(myClass3.toString());

  MyClass myClass4 =
      new MyClass.overloadedContructorNamedArguemnts(age: 42, name: "Amit");

  print(myClass4.toString());
}
amitsriv99
  • 113
  • 1
  • 4
3

Dart doesn't support parameter overloading (having multiple functions of the same name but with different parameters). This applies to constructors as well - that's the reason why in SDK there're so many classes with named constructors.

In Dart you can use Default Constructor, Named Constructor, Factory Method and Static Method to instantiate classes:

class A {
  // Default constructor
  A() : msg = '1';
  
  // Named constructor with positional param
  A.message(this.msg);
  
  // Factory method with named param
  factory A.underscore({String msg = ''}) {
    return A.message('_'+msg);
  }
  
  // Factory method with arrow func body
  static A bang(msg) => A.message('!'+msg); 
  
  final String msg;
}

void main() {
  print(A().msg);
  print(A.message('2').msg);
  print(A.underscore(msg: '3').msg);
  print(A.bang('4').msg);
}

Output:

1
2
_3
!4
Maxim Saplin
  • 4,115
  • 38
  • 29
2

You can use factory constructors

factory Player.fromPlayer(Player another) => Player(another.name, another.color);
Faruk
  • 5,438
  • 3
  • 30
  • 46
0

As Günter Zöchbauer already specified in his answer:

You can only have one unnamed constructor, but you can have any number of additional named constructors in Flutter.

  • By using named constructor you can create multiple constructors in the same class.
  • Each constructor will have a unique name. So that you can identify each of them.

Syntax for named constructor :

class_name.constructor_name (arguments) { 
   // If there is a block of code, use this syntax

   // Statements
}

or

class_name.constructor_name (arguments); 
   // If there is no block of code, use this syntax

For more insights Click Here

To know about various types of constructors in Flutter Click Here

Deepam Gupta
  • 2,374
  • 1
  • 30
  • 33
0

i had found solution to solve this problem depend on checked the type of data you are passed it to function

Try this Solution

Mahmoud Salah Eldin
  • 1,739
  • 16
  • 21
0

Class User{
      User();
      User.fromName(this.name);
      
      String? name;
    }
  • There are **eight existing answers** to this question, including a top-voted, accepted answer with **two hundred votes**. Are you _certain_ your solution hasn't already been given? If not, why do you believe your approach improves upon the existing proposals, which have been validated by the community? Offering an explanation is _always_ useful on Stack Overflow, but it's _especially_ important where the question has been resolved to the satisfaction of both the OP and the community. Help readers out by explaining what your answer does different and when it might be preferred. – Jeremy Caney Jan 05 '22 at 00:07
0

If you want to do some more elaborated property calculation (I'm a Swift guy), you can do like this:

class FooProvider {
  int selectedFoo;

  FooProvider(List<String> usageObjects)
      : selectedFoo = firstOne(usageObjects);

  static int firstOne(List<String> usageObjects) {
    return 2;
  }
}
Rudolf J
  • 517
  • 4
  • 10
0

Try this: make the properties you need to pass to the other constructor as optionals.

class Person{
  String name;
  int? age;

  Person(this.name, this.age);

  Person.veryOld(this.name){
    age = 60;
  }

  @override String toString() {
    return "name: $name\nage: $age";
  }
}
Tyler2P
  • 2,324
  • 26
  • 22
  • 31