Default constructor cannot be referenced error (Visual studios 2019)

Viewed 5108

I am getting an error at the bottom of my code when trying to reference my revised subclass, as follows:

default constructor of 'Revisedcipher' cannot be referenced -- it is a deleted function

I'm not entirely sure what that means or how to fix that. Any help with this would be greatly appreciated.

My code:

#include <iostream>
#include <string>

using namespace std;

class SubstitutionCipher {
public:
//Define your key which is a permutation of 26 alphabets
string key;

//Constructor to create an instance which initializes the key with the given permutation
SubstitutionCipher(string k) {
    key = k;
}

//function to encode a string
string encode(string data) {
    //initialize encoded data
    string encodedData = data;
    //replace each character in encodedData with the corresponding mapped data in key. We subtract a char with 'A' to get its position
    for (int i = 0; i < data.length(); i++) {
        encodedData[i] = key.at(data.at(i) - 'A');
    }
    //return the encoded data
    return encodedData;
}

//function to decode a string
string decode(string data) {
    //initialize decoded data
    string decodedData = data;
    //replace each character in decodedData with the corresponding reverse mapped data in key. We add the position with 'A' to get the corresponding char
    for (int i = 0; i < data.length(); i++) {
        decodedData[i] = key.find(data.at(i)) + 'A';
    }
    //return the decoded data
    return decodedData;
}

};

class Revisedcipher : public SubstitutionCipher
{
public:
void encrypt(string text, int s)
{
    string result = "";

    // traverse text
    for (int i = 0; i < text.length(); i++)
    {
        // apply transformation to each character
        // Encrypt Uppercase letters
        if (isupper(text[i]))
            result += char(int(text[i] + s - 65) % 26 + 65);

        // Encrypt Lowercase letters
        else
            result += char(int(text[i] + s - 97) % 26 + 97);
    }

    // Return the resulting string
 //   return result;
    cout << "\n C_Cipher: " << result;
}
};

//main() method to test the implementation
int main() {
    SubstitutionCipher cipher("ZYXWVUTSRQPONMLKJIHGFEDCBA");
    string data = "HJOIEBSOMN";
    string encodedData = cipher.encode(data);

    cout << data << " encoded as " << encodedData << endl;
    string decodedData = cipher.decode(encodedData);
    cout << encodedData << " decoded as " << decodedData;
    Revisedcipher cc;
    cc.encrypt(data, 4);
}
2 Answers

As you have provided a non-default constructor (one with an argument) for your base class, SubstitutionCipher but no default constructor (i.e. one with no argument), the latter is implicitly deleted. Further, as your derived class, Revisedcipher provides no constructor, it does not override the deleted base class constructor.

To fix this, you need to either define a default constructor for your base class, or provide one for the derived class (or both). You can also do this using a default value for the argument.

Here's how to do it for the derived class:

class Revisedcipher : public SubstitutionCipher {
public:
    // Call the base class constructor with a given string, or the 'default' if none...
    Revisedcipher(string rk = "[default]") : SubstitutionCipher(rk) {}
    void encrypt(string text, int s)
    {
    //... and so forth

Alternatively, you can provide a default std::string argument for your base clase constructor:

SubstitutionCipher(string k = "[default value]") {
    key = k;
}

Your base type SubstitutionCipher has a user defined constructor, which will disable compiler's auto-generation of the default constructor.

This line:

SubstitutionCipher(string k) {
    key = k;
}

Any type which inherits this must define a constructor which calls SubstitutionCipher(string) with some value.

There are three ways around it that I can think of:

  1. You can either direct compiler to generate default constructor as it would have otherwise through this line:

     SubstitutionCipher() = default;
    

    but I don't think that's a very good idea since you'll either have to hard-code the key or leave it blank. Neither is a good option.

  2. You can add a constructor to Revisedcipher which takes a key parameter and passes that along to the base class, like this:

      Revisedcipher(const string& key) : SubstitutionCipher(key) { }
    
  3. You may consider adding a default constructor to Revisedcipher instead, which passes some hard-coded key to base.

      Revisedcipher() : SubstitutionCipher("your hard-coded key") { }
    

P.S.: There is a fourth way. You can assign a default value to key parameter in the base class.

P.P.S.: The fifth way around this would be to get the key from some external source rather than as a constructor argument.

Related