Inheritance/Polymorphism example
This is an example of inheritance and polymorphism, two ideas of Object-Oriented Programing.
Attribute
is an abstract class that is implemented by StringAttr
and IntegerAttr
. This allows us to use containers like std::vector
or std::list
to store both of these types.
Just like the other example, this one has no leaks or warnings.
NOTE: I’m not saying this is attributes should be implemented. I’m just using it as a means to explain these features.
#include <stdio.h>
#include <climits>
#include <vector>
#include <string>
#include <string.h>
#include <memory>
class Attribute
{
public:
Attribute(const char *n);
char * toString() const; // const after the arguments means that this function does not modify anything internal to Attribute
virtual ~Attribute(); // a virtual destructor must be defined so the derrived classes' destructors are called.
char * name; // every attribute has a name, we should define it once here.
protected:
virtual char * toString_impl() const = 0; // the = 0 at the end makes this a pure-virtual function.
// Pure-virtual functions must be overrided by derrived classes.
// Having a pure-virtual function makes this class an Abstract Class
};
Attribute::Attribute(const char *n)
{
name = strdup(n);
printf("Creating attribute with name %s\n", name);
}
Attribute::~Attribute()
{
free(name);
}
// Returns an allocated string, must be freed by caller
// This is a "wrapper" to all the attribute's toString_impl().
char *
Attribute::toString() const
{
printf("Calling toString on %s\n", name);
return toString_impl();
}
class StringAttr : public Attribute {
public:
StringAttr(const char *n, const char *s);
~StringAttr();
protected:
char * toString_impl() const override; // override tells us that this function overrides the base class
private:
char * value;
};
StringAttr::StringAttr(const char *n, const char *s) : Attribute(n) // Call Attribute's (const char *) constructor
{
printf("Creating String Attr\n");
value = strdup(s); // Since we're already calling Attributes constructor, we just need to fill in the value
}
StringAttr::~StringAttr()
{
free(value);
}
char *
StringAttr::toString_impl() const
{
char s[100];
snprintf(s, sizeof(s), "%s %s", name, value);
return strdup(s);
}
class IntegerAttr : public Attribute {
public:
IntegerAttr(const char *n, const char *s);
IntegerAttr(const char *n, int val);
protected:
char * toString_impl() const override;
private:
int value;
};
IntegerAttr::IntegerAttr(const char *n, const char *s) : Attribute(n)
{
printf("Creating Integer Attr\n");
value = strtol(s, nullptr, 10);
}
IntegerAttr::IntegerAttr(const char *n, int val) : Attribute(n)
{
printf("Creating Integer Attr\n");
value = val;
}
char *
IntegerAttr::toString_impl() const
{
char s[100];
snprintf(s, sizeof(s), "%s %d", name, value);
return strdup(s);
}
int
main()
{
std::vector<Attribute *> attrs;
attrs.push_back(new StringAttr("jobid", "3.abcd")); // We can "upcast" StringAttr to the Attribute base class.
attrs.push_back(new IntegerAttr("stime", "1600001031"));
attrs.push_back(new StringAttr("select", "1:ncpus=1"));
attrs.push_back(new IntegerAttr("qtime", 1600003201));
// attrs.push_back(new Attribute("badattr")); // This fails because Attribute is an abstract class and cannot be instantiated
for (const auto &attr : attrs) {
char * out = attr->toString();
if (auto p = dynamic_cast<StringAttr *>(attr)) { // We can "downcast" Attributes to their derived class.
printf("String Attribute! [%s]\n", out);
}
else if (auto p = dynamic_cast<IntegerAttr *>(attr)) {
printf("Integer Attribute! [%s]\n", out);
}
else {
printf("%s\n", out);
}
free(out);
}
for (auto &attr : attrs) {
delete(attr);
}
}
This outputs:
Creating attribute with name jobid
Creating String Attr
Creating attribute with name stime
Creating Integer Attr
Creating attribute with name select
Creating String Attr
Creating attribute with name qtime
Creating Integer Attr
Calling toString on jobid
String Attribute! [jobid 3.abcd]
Calling toString on stime
Integer Attribute! [stime 1600001031]
Calling toString on select
String Attribute! [select 1:ncpus=1]
Calling toString on qtime
Integer Attribute! [qtime 1600003201]