Question

I have written some code to calculate the RSA cryptographic algorithm. The program uses classes and inheritance because I want to calculate a public and private key for multiple users. There is a parent class rsa and child classes public_key and private_key.

When compiling the code below, I get many errors. All of them are about the derived classes not having the available fields in their respective constructors (see error message below code). However, these variables are defined with the protected access modifier in the parent class, so they should be accessible to the child class.

One side note: I had the function key in both of the child classes, but I thought it would be better to put it once in the parent class, is this right?

Here is the code:

#include <iostream>
#include <math.h>

using namespace std;

class rsa
{
protected:
    int p, q, d, m, n, f, e, c, end, k;

public:
    rsa() : n(0), e(0), c(0), k(0), end(0), f(0)
    { }

    void set(int , int , int, int);

    int key()
    {
        n = p * q;
        f = (p - 1) * (q - 1);

        for (k; end < 1; k++)
        {
            if ((1 + k * f) % d == 0) 
            {
                end = 2;
                e = (1 + k * f) / d;
            }
        }

        c = int(pow(m, e)) % n;

        return c;
    }
};

void rsa::set(int p_, int q_, int d_, int m_)
{
    p = p_;
    q = q_;
    d = d_;
    m = m_;
}

class public_key : public rsa
{
public:
    public_key() : n(0), e(0), c(0), k(0), end(0), f(0)
    { }
};

class private_key : public rsa
{
public:
    private_key() : n(0), e(0), c(0), k(0), end(0), f(0)
    { }
};

int main()
{
    public_key usr1, usr2;
    private_key usr1r, usr2r;

    usr1.set(11, 5, 23, 9);
    usr2.set(13, 7, 97, 6);
    usr1r.set(17, 7, 51, 8);
    usr2r.set(11, 17, 51, 4);

    cout << "Public key of user 1: " << usr1.key() << endl;
    cout << "Public key o user 2: " << usr2.key() << endl;

    cin.get();

    return 0;
}

One of the errors:

error: class ‘private_key’ does not have any field named ‘e’
   private_key () : n(0), e(0), c(0), k(0), end(0), f(0) {} ;

All the other errors are the same but the field name changes.

Was it helpful?

Solution

The error has nothing to do with the access level of the members of class rsa. Even if you declare those members public you will still get the error. The problem is that a derived class's initialization list is run solely in the context of itself, you do not have access to base class members.

You can however access base class members (that are public or protected) in the body of a derived class constructor. Ex:

class public_key : public rsa
{
public:
    public_key()
    {
        n = 0;
        e = 0;
        c = 0;
        k = 0;
        end = 0;
        f = 0;
    }
};

class private_key : public rsa
{
public:
    private_key()
    {
        n = 0;
        e = 0;
        c = 0;
        k = 0;
        end = 0;
        f = 0;
    }
};

Though the above code uses assignment instead of initialization, it does the exact same thing under the hood for primitive types, which all of those members are.

Still, though the above code works, it is the wrong way of doing what you want. You have already written a constructor for class rsa, so one way to avoid duplicating code is to call your existing constructor from the initialization list.

class public_key : public rsa
{
public:
    public_key() : rsa()
    { }
};

class private_key : public rsa
{
public:
    private_key() : rsa()
    { }
};

However note that rsa() is the default constructor (since it has no parameters) so it will automatically be called by any constructor of the derived class (unless you specify some other rsa constructor in the initialization list).

class public_key : public rsa
{
public:
    public_key()
    { } // rsa() will be called automatically
};

class private_key : public rsa
{
public:
    private_key()
    { } // rsa() will be called automatically
};

But now that your derived class's have empty default constructors, you do not even need them (unless you plan to add more logic).

class public_key : public rsa
{
public:
    // rsa() will still be called automatically when declaring an instance of public_key
};

class private_key : public rsa
{
public:
    // rsa() will still be called automatically when declaring an instance of private_key 
};

As to your side note on the key() function, if the implementation of key() was the same in both child classes then yes, you only need it once in the parent class. You should always avoid code duplication so even if a small part of key() needed to be customized for each child class, you are better off writing a virtual function in the base class that key() can call as part of the calculation. Then, in each child class, override the virtual function with whatever specialization is necessary. Thus all the shared code can remain in the parent class key() function.

OTHER TIPS

According to the C++ Standard (12.6.2 Initializing bases and members, paragraph #2)

Unless the mem-initializer-id names the constructor’s class, a non-static data member of the constructor’s class, or a direct or virtual base of that class, the mem-initializer is ill-formed.

So mem-initializers of the derived classes in your program are ill-formed and the compiler issues an error.

It is the base class constructor that should initialize its data members.

There is no any sense to define the constructor of class for example public_key the following way as

public_key () : n(0), e(0), c(0), k(0), end(0), f(0) {} ;

because at first the constructor of the base class will be called

rsa () : n(0), e(0), c(0), k(0), end(0), f(0) {};

and it will initialize the data members.

So it is enough to write

rsa () {}

or

rsa () = default;

It should be private_key() : rsa() {};

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top