...
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.
Code Block | ||||
---|---|---|---|---|
| ||||
#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 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); } } |
...