Question simplified: an expression is a parameter. It includes 2 objects of type parameter. But, is that parameter a string_class, ID_class, or Expression_class parameter? If I just say Parameter, it won't have these certain characteristics, will it? How do I have these objects, use logic, and then I can know if the private data members of Expression are string, id, or expression parameters? Sometimes I want that left parameter to be an expression, sometimes I want it to be a string, sometimes an ID.
class Parameter
{
public:
private:
};
class String_class : public Parameter
{
public:
String_class(string in_string)
private:
string my_string;
};
class ID_class : public Parameter
{
public:
insert_id(string in_ID);
private:
string my_ID;
};
class Expression_class : public Parameter
{
private:
Parameter left_parameter;
Parameter right_parameter;
string op;
public:
};
Lots of ways to do this...
enum ParameterType{
PT_INVALID_TYPE = -1,
PT_OPERATION_TYPE= 0,
PT_STRING_TYPE,
PT_ID_TYPE,
PT_INT_TYPE,
...
PT_MAX_TYPES
}
class Parameter {
public:
...
virtual ParameterType GetType() = 0;
virtual string ToString() = 0; // GetValue(), etc...
}
class String_class : public Parameter
{
public:
String_class(string in_string){}
virtual ParameterType GetType() override { return PT_STRING_TYPE; }
virtual string ToString() override {return my_string;};
private:
string my_string;
};
class ID_class : public Parameter
{
public:
insert_id(string in_ID);
virtual ParameterType GetType() override { return PT_ID_TYPE; }
virtual string ToString() override {return my_ID;};
private:
string my_ID;
};
enum OperationType {
OP_INVALID_OP = -1,
OP_CONCATENATE = 0,
OP_ADD,
OP_COMPARE_EQUAL,
OP_COMPARE_LESS_THAN,
OP_XOR,
... // whatever
OP_MAX,
}
class Expression_class : public Parameter
{
private:
Parameter* left_parameter;
Parameter* right_parameter;
string op;
public:
};
Some usage examples...
class Expression_class : public Parameter
{
private:
Parameter* left_parameter;
Parameter* right_parameter;
string op;
public:
Expression_class(string _op, Parameter* lhs, Parameter* rhs):
left_parameter(lhs), right_parameter(rhs), op(_op)
{
// alternatively
left_parameter = lhs;
right_parameter = rhs;
op = _op;
}
~Expression_class(){
left_parameter = nullptr;
right_parameter = nullptr;
}
virtual ParameterType GetType() { return PT_OPERATION_TYPE; };
virtual string ToString() { return eval(); }
protected:
string eval() {
if(left_parameter.GetType() != PT_ID_TYPE) return "Invalid left_parameter.";
if(right_parameter.GetType() != PT_STRING_TYPE) return "Invalid right_parameter";
switch(op){ // op is better as OperationType than string
case OP_CONCATENATE : return left_parameter.ToString() + " " + right_parameter.ToString();
// ...
}
if(CompareNoCase(op, "+") == 0)
return left_parameter.ToString() + " " + right_parameter.ToString();
return "Invalid Opertaion";
}
};
String_class employee_name("Rick");
String_Id employee_id("007");
Expression_class exp(OP_CONCATENATE, &employee_id, employee_name);
return exp.ToString();
Notes This is not the only way to do it, and as you use your class, you'll figure out short cuts to do less work.
Related
I have a class that is called Object, this class's header is:
class DLL_SPEC Object {
public:
Object();
virtual ~Object();
virtual std::string getString() const;
virtual void setString(std::string value);
virtual int getInt() const;
virtual void setInt(int value);
virtual double getDouble() const;
virtual void setDouble(double value);
virtual bool isType(FieldType type) const;
};
And my child classes are as follows:
class DLL_SPEC IntObject : public Object {
public:
IntObject() : value(0) {}
IntObject(int v) : value(v) {}
void setInt(int value) override { this->value = value; };
int getInt() const override { return this->value; };
bool isType(FieldType type) const override;
private:
int value;
};
class DLL_SPEC DoubleObject : public Object {
public:
DoubleObject() : value(0.0) {}
DoubleObject(double v) : value(v) {}
void setDouble(double value) override { this->value = value; };
double getDouble() const override { return this->value; };
bool isType(FieldType type) const override;
private:
double value;
};
class DLL_SPEC StringObject : public Object {
public:
StringObject() : value("") {}
StringObject(std::string v) : value(v) {}
void setString(std::string value) override { this->value = value; };
std::string getString() const override { return value; };
bool isType(FieldType type) const override;
private:
std::string value;
};
Now, the problem is, I have an array of Objects and I want to get a string representation of a StringObject.
I call array[0].getString() and even though the object is of type StringObject, the method that gets called is the one is the base class, which I understand.
So, how would I go about implementing that whenever I call getString() on the base class it goes to the child one of the SAME object?
I've tried using this method:
std::string Object::getString() const
{
return dynamic_cast<StringObject*>(this).getString();
}
but then I get an error stating I cannot cast away const or any type qualifier, which is fixed by deleting const modifier (which I MUST leave there as it's according to the task), but then I get another one stating that no suitable constructor exists. So how would I go about implementing this and getting this base class to use the one of the child one?
EDIT: Added a small example that goes into the getString method of Object class and not the StringObject class.
int findPersonId(std::string whereName)
{
Db* db = Db::open("database");
Table* people = db->openTable("table");
auto iteratorTable = table->select();
while (iteratorTable->moveNext())
{
for (size_t i = 0; i < table->getFieldCount(); i++)
{
if (table->getFields()[i]->getName() == "id")
{ //this one beneath goes to the base class and not StringObject
std::string foundRow = iteratorPeople->getRow()[i]->getString();
if (foundRow == whereName)
{
return iteratorTable->getRowId();
}
}
}
}
return 0;
}
Note: The Table* is 2D array that consists of Object** (array that contains StringObject, IntObject, DoubleObject). The method .getRow() return the Object** array that consists of StringObject ...
The way I initiate the objects that go into the array is
Table* table= db->openOrCreateTable("table", 2, userFields); //this creates a 2d array
StringObject* name = new StringObject("Joseph");
IntObject* id = new IntObject(5);
Object** row = combineToRow(id, name);
table->insert(row); //insert an array into 2D array
The method combineToRow is just a simple convertor to Object**.
template<typename A, typename B>
Object** combineToRow(A a, B b) {
return new Object * [2]{ a, b };
}
You have not implemented a getString method for your IntObject, and since you didn't override it you are calling the base method. Once you implement it like this
class IntObject : public Object {
...
virtual std::string getString() const { return std::to_string(value); };
...
};
then you can call it.
int main(){
StringObject* name = new StringObject("Joseph");
IntObject* id = new IntObject(5);
Object** row = combineToRow(id, name);
std::cout << row[0]->getString() << " " << row[1]->getString();
}
5 Joseph
See working version here
I have encountered a problem with creating new class objects.
The abstract class is called SimpleList, currently doesn't do anything on its own.
template<class T>
class SimpleList {
public:
string ListName;
SimpleList(){
};
string getName(){
return ListName;
};
};
template<class T>
class Queue : public SimpleList<T> {
public:
string ListName;
Queue(string& name){
ListName = name;
}
string getName(){
return ListName;
}
};
And here is where I am attempting to assign 'pQLi' to a new Queue, where Queue is a derived class.
SimpleList<int> *pQLi;
if (indicator == 'i' ){
pQLi = new Queue<int>(name1);
}
But whatever I do to print out the name of pQLi (or access any data from it, but in the simplest case ) outside of the Queue, only ' ' is coming out. For example, if I do this
cout <<(*pQLi).getName() <<"\n";
Instead of printing out the ListName, a blank character comes out
its as simple as it is. Make your base class getName() virtual as follows. Since you are care of the content of pointer, you need a late binding of the object.
template<class T>
class SimpleList
{
public:
string ListName;
SimpleList() = default;
virtual string getName(){
return ListName;
};
};
However, I do not understand, why you need a template class for this. You have not used the type(T) anywhere.
And try to use initializer_list whenever possible and smart pointers are good to use in following cases. I have made a small correction as follows. Hope this has answered your question.
#include <iostream>
template<class T>
class SimpleList
{
private:
std::string ListName;
public:
SimpleList() = default;
virtual ~SimpleList(){}
virtual const std::string& getName()const
{ return ListName; };
};
template<class T>
class Queue : public SimpleList<T>
{
private:
std::string ListName;
public:
Queue(const std::string& name)
:ListName(name) {}
const std::string& getName()const
{ return ListName; }
};
int main()
{
SimpleList<int> *pQLi;
char indicator = 'i';
std::string name1 = "nothing";
if (indicator == 'i' ){
pQLi = new Queue<int>(name1);}
std::cout <<(*pQLi).getName() <<"\n";
delete pQLi;
pQLi = nullptr;
return 0;
}
I have one problem on conversion of one class to base.
This is the code :
#define Derive_NTag_CRTP(Type) class Type: public NTagBase<Type>
template<typename Derived>
class NTagBase{
public:
NTagBase(var name) { this->_name = name; }
NTagBase(const NTagBase & ntag) { this->_name = ntag._name; }
NTagBase* append(NTagBase<Derived> *item) { _children.push_back(item); return this; }
private:
var _name;
vector<NTagBase *> _children;
};
Derive_NTag_CRTP(NTag){
public:
NTag(var name) : NTagBase(name) { }
NTag(const NTagBase & ntag) : NTagBase(ntag) { }
};
Derive_NTag_CRTP(NTagInput){
public:
NTagInput(var type) : NTagBase("input") { _type = type; }
NTagInput(const NTagBase & ntag) : NTagBase(ntag) { }
private:
var _type;
};
int main(int argc, char **argv, char **envv)
{
NTag div("div");
NTagInput button("button");
div.append(new NTag("span"));
div.append(&button);// Error 1 error C2664: 'NTagBase<Derived>::append': can not convert parameter 1 from 'NTagInput *' to 'NTagBase<Derived> *'
}
How can I fix that without do one explicit cast?
PS: I need to have one vector of pointers of base class and append into that all kind of classes inherited.
div is NTag, i.e. NTagBase<NTag>. button is NTagInput, i.e. NTagBase<NTagInput>, while div's append() expects a NTagBase<NTag> which is unrelated. You should change append to something like
template <typename D>
NTagBase* append(NTagBase<D> item) { ... }
However, you still cannot store items of different types in a single vector. Better make a non-template e.g. Base of NTagBase and let your vector contain pointers (or std::unique_ptr) to Base.
div.append (...) clearly need to be overloaded because after inherited from the base, it wouldn't understand the second signature ie div.append(&button); or you can create a wrapper class that pack every object type to it own define and provide a mechanism for reversing back to the original type.
Alternatively , just overload any necessary function .
class NTagInput;
class AppendInputRegister;
template<typename Derived>
class NTagBase{
public:
NTagBase(string name) { this->_name = name; }
NTagBase(const NTagBase & ntag) { this->_name = ntag._name; }
NTagBase* append(NTagBase<Derived> *item) {
_children.push_back((NTagBase *)item);
return this;
}
private:
string _name;
vector<NTagBase *> _children;
};
class NTag: public NTagBase<NTag>{
public:
NTag(string name) : NTagBase(name) { }
NTag(const NTagBase & ntag) : NTagBase(ntag) { }
NTagBase* append(NTagBase<NTagInput> *item) {
append((NTagBase<NTag> *)item);
}
NTagBase* append(NTagBase<NTag> *item) {
NTagBase::append((NTagBase<NTag> *)item);
}
};
class NTagInput: public NTagBase<NTagInput>{
public:
NTagInput(string type) : NTagBase("input") { _type = type; }
NTagInput(const NTagBase & ntag) : NTagBase(ntag) { }
private:
string _type;
};
I am trying to do this:
class Parameter
{
public:
Parameter(){};
~Parameter(){};
};
class Address : public Parameter
{
public:
Address(uint16_t val) : value(val){};
Address(const Address& b) : value(b.value){};
~Address(){};
private:
uint16_t value;
};
class Constant : public Parameter
{
public:
Constant(int val) : value(val){};
Constant(const Constant& b) : value(b.value){};
~Constant(){};
private:
int value;
};
How can I add set and get methods for the parent class Parameter so that when I create a Constant or Address object, I can use the parent methods to set and get the variable value?
Not sure what you meant, but here is a try:
template <typename T>
class Parameter
{
public:
const T& getValue() { return value; }
protected:
T value;
};
class Address : public Parameter<uint16_t>
{
public:
Address() { value = 2154; }
// ...
}
class Name : public Parameter<std::string>
{
public:
Name() { value = "John Doe"; }
// ...
}
Later you can do:
Address address;
Name name;
cout << name.getValue() << " lives at house no " << address.getValue();
// outputs "John Doe lives at house no 2154".
You could implement it as a pure virtual function and over ride it in the below classes?
I have this basic setup:
enum{
BASE,
PRIMITIVE,
...
};
class IUnknown{
public:
bool inline is(int type){return inv_type == type;}
private:
enum {inv_type = BASE};
};
class Primitive: public IUnkown{
private:
enum {inv_type = PRIMITIVE};
};
My problem is that I would want to be able to call is on a Primitive instance and have it return true when type is equal to the value in the enum I have declared in the Primitive class.
The only solution I have found is to declare the 'is' function as virtual and have a copy in every subclass, but I wondered if it would be possible to somehow redefine the enum and have the is function in IUnkown take the value from there
You could have your IUnknown class define a protected constructor (which would then have to be called from each derived class). It would take one of the enum values and store it. The stored value would then be compared against in the is() method.
If you don't like this, and prefer to add a virtual is() method to IUnknown, but don't want to have to define it in every derived class, you could do this:
template <int Tinv_type>
class IUnknownT : public IUnknown{
public:
virtual bool is(int type){return inv_type == type;}
protected:
enum {inv_type = Tinv_type};
};
class Primitive: public IUnknownT<PRIMITIVE>{
};
enums by themselves don't take up storage space because they're just lists of acceptable values for an enum variable. You have to have some runtime storage going on for a virtual function to actually work with the runtime type of the object. I would just use an int or something:
enum{
BASE,
PRIMITIVE,
...
};
class IUnknown{
public:
bool is(int type) const {return inv_type == type;}
protected:
IUnknown(int type) : inv_type(type) { }
private:
const int inv_type;
};
class Primitive: public IUnkown{
private:
Primitive() : IUnknown(PRIMITIVE) { }
};
Why not go all out and use strings instead of enums.
const char * baseStr = "base";
const char * derived1Str = "derived1";
const char * derived2Str = "derived2";
class base
{
public:
virtual bool is(const char * str)
{
return strcmp(baseStr, str) ? false : true;
}
};
class derived1 : public base
{
public:
bool is(const char * str)
{
if ( strcmp(derived1Str, str) )
return base::iA(str);
return true;
}
};
class derived2 : public derived1
{
public:
bool is(const char * str)
{
if ( strcmp(derived2Str, str) )
return derived1::is(str);
return true;
}
};
This has the benefit that this
base * b = new derived2();
bool is = b->isA(baseStr);
sets is to true.