#polymorphic design

16 messages · Page 1 of 1 (latest)

calm lodge
#

I am trying to understand the cleanest way to design a credentials base class and subclasses.
Say I have base class Credentials. I have multiple different credential types, for example username/password, or certificate etc. So it would make sense to have a child class of Credentials called 'Password' and another called 'Certificate'.
Question 1 - if I make Credentials have a get() method, how do I make it return only the type of credentials I have stored in there? For example if PasswordCred is of type 'Password' and I call the parent get() method, how does the parent know (or should it ever actually know) what to return based on the sub class?
The child class Password could have two members, 'username' and 'password. The child class 'Certificate' could have three members 'certificate', 'private key', 'certificate chain'.
Lets say I have another class called AuthenticateBase, with a method Login which requires Credentials.
Question 2 - If I derive a class from this called CertificateAuthentication, and override the Login method, how would I define or code this in a way that ensures that I'm passing a Certificate and not a Password?

I assume this is a common polymorphic pattern but I just cant wrap my head around the right way to go about it!

twin badgeBOT
#

When your question is answered use !solved to mark the question as resolved.

Remember to ask specific questions, provide necessary details, and reduce your question to its simplest form. For tips on how to ask a good question use !howto ask.

calm lodge
#

maybe its a template thing? or composition? or variant? 🤷‍♂️

shadow folio
#

Inheritance is best used when there is a "is-a" relationship. Composition is a "has-a" relationship. So using that you can try and deduce whether or not it makes sense for these to share a common interface which I think it can do, but not at the data level. Since a user name and password and certificates don't really have a "is-a" or a "has-a" relationship.
Now for you to have a common get with essentially a co-variant return type you would have to use a variant, only issue with that is the base class would have to know about all the types of "Credentials" you would have in advance which would be a pain to manage if you were to add one.
What you could do is just have the data as a pod like: ```cpp
struct PasswordCredentials {
std::string username;
std::string password;
};

struct CertificateCredentials {
std::string certificate;
std::string privateKey;
std::string certificateChain;
};

Then have a templated Authentication class that has specialisations for these type  ```cpp
template <typename CredentialT>
class Authenticator {
public:
    void Login(const CredentialT& credentials) {}
};

Then specialise something like so ```cpp

template <>
void Authenticator<PasswordCredentials>::Login(const PasswordCredentials& credentials) {
// stuff for dealing with passwords
}

template <>
void Authenticator<CertificateCredentials>::Login(const CertificateCredentials& credentials) {
// stuff for dealing with certificates
}

This way you have a common login function but still have distinct types for storing the credentials. 
You could also drop classes all together and just have login functions with overloads, but I dunno what else the Authentictor class would do.
calm lodge
#

this is really helpful. i think where i'm coming unstuck is that logically both of these things are types of credentials, but their usage has nothing in common and will ultimately only work if the caller knows in advance what type of credential they are intending to work with

#

what does make this a bit awkward is that i have a pure virtual class with a method for Login, so when i override it i will have the templating to deal with

shadow folio
shadow folio
calm lodge
#

yes thats really the core of the what ive been trying to wrap my head around

shadow folio
#

I don't really see how you could work with a common base for credentials without having to do some nasty dynamic casting at some point either.

#

Personally I would use the templated method since it does allow the authentication to share functionality in a way but you could just do an overload ```cpp
bool Login(const PasswordCredentials& credentials) {
// stuff for dealing with passwords
}

bool Login(const CertificateCredentials& credentials) {
// stuff for dealing with certificates
}

Then just return a boolean value as to whether or not the credentials could be identified
calm lodge
#

ah yeah an overload might also work

#

i cant remove the pure virtual base class unfortunately but overloads would be ok

#

let me try that. and thank you so much for the thoughtful response

twin badgeBOT
#

@calm lodge Has your question been resolved? If so, type !solved :)

calm lodge
#

!solved