Home > database >  Super class doesn't have a zero argument constructor
Super class doesn't have a zero argument constructor

Time:03-30

I am trying to use a base class in a data model.

I have a base class of Symptoms and I want to add Headache as an extension of Symptom

Right now this is my code

import 'package:cloud_firestore/cloud_firestore.dart';

class Symptom {
  final String id;
  final String path;
  final DateTime startTime;
  final String? type;

  String get patientId => path.split('/')[1];

  Symptom({
    required this.id,
    required this.path,
    required this.startTime,
    this.type,
  });

  factory Symptom.fromJson(
    String id,
    String path,
    Map<String, Object?> doc,
  ) {
    final start = doc['startTime'] as Timestamp;
    return Symptom(
      id: id,
      path: path,
      startTime: start.toDate(),
      type: doc['type'] as String?,
    );
  }

  Map<String, Object?> toJson() {
    return {
      'startTime': startTime,
      'type': type,
    };
  }
}

class Headache extends Symptom {
  int? intensity;
  DateTime? endTime;
  List<String> symptoms;
  List<String> effects;
  Map<String, int> medications;
  bool? medsEffective;
  String? notes;

  Duration? get duration => endTime?.difference(startTime);

  double get hours {
    final inHours = duration?.inHours ?? 0;
    final inMins = duration?.inMinutes ?? 0;
    if (inHours < 1) {
      return inMins / 60;
    } else {
      return inHours.toDouble();
    }
  }

  Headache({
    this.intensity,
    this.medsEffective = false,
    this.endTime,
    this.notes,
    this.symptoms = const [],
    this.effects = const [],
    this.medications = const {},
  });

  factory Headache.fromJson(
    String id,
    String path,
    Map<String, Object?> doc,
  ) {
    final start = doc['startTime'] as Timestamp;
    final end = doc['endTime'] as Timestamp?;

    final tempMeds = doc['medications'] as Map<String, dynamic>;
    return Headache(
      intensity: doc['intensity'] as int?,
      notes: doc['notes'] as String?,
      endTime: end?.toDate(),
      medsEffective: (doc['medsEffective'] as bool?),
      symptoms:
          (doc['symptoms'] as List).map((item) => item as String).toList(),
      effects: (doc['effects'] as List).map((item) => item as String).toList(),
      // ignore: unnecessary_lambdas
      medications: tempMeds.map((key, value) => MapEntry(key, value)),
    );
  }

  Map<String, Object?> toJson() {
    return {
      'intensity': intensity,
      'notes': notes,
      'endTime': endTime,
      'symptoms': symptoms,
      'medsEffective': medsEffective,
      'effects': effects,
      'medications': medications,
    };
  }
}

When I try to do

Headache({
    this.intensity,
    this.medsEffective = false,
    this.endTime,
    this.notes,
    this.symptoms = const [],
    this.effects = const [],
    this.medications = const {},
  });

It gives me an error

The superclass 'Symptom' doesn't have a zero argument constructor. Try declaring a zero argument constructor in 'Symptom', or explicitly invoking a different constructor in 'Symptom'

I am wondering how to fix this but also why is this error coming up and why does it need a zero argument constructor. Is extending a base class of a data model a good practice or should I shy away from this and make an entirely separate data model for headaches separate from symptoms?

CodePudding user response:

If you don't explicitly call the super constructor in the constructor of child class, the compiler will try to implicitly call the default constructor of the super class (which, in this case, would be Symptom()).

Since you've defined a Symptom constructor that takes several arguments, there is no automatic default constructor for the class, so the Headache constructor is unable to initialize the fields of the super class.

You can resolve this by having your Headache constructor take additional arguments to initialize the super class:

Headache({
  this.intensity,
  this.medsEffective = false,
  this.endTime,
  this.notes,
  this.symptoms = const [],
  this.effects = const [],
  this.medications = const {},
  required String id,
  required String path,
  required DateTime startTime,
  String? type,
}): super(
  id: id, 
  path: path,
  startTime: startTime,
  type: type,
);

CodePudding user response:

Refer to Michael's answer regarding the error you are receiving, but I want to comment on the how you are structuring your objects.

I would make a generic Illness class, with the name of the illness (e.g. "Headache") as a property so that you don't need to predefine every possible type of illness. Then I would suggest that Symptom should have a property field that holds an Illness object. If you want to constrain the types of illnesses, you can make the illness an enum that defines all possible illness types.

If you decide you have a good reason for directly creating classes for each specific illness, create an abstract Illness class and Headache should inherit from it so that all of the illnesses are interchangeable throughout the application.

  • Related