Heterogeneous container of base class when the derived instances are not pointers - c++
I have a base class and I want to store instances of its derivatives in a collection of some sort.
At first I created a map:
std::map<int, Variable> varriableItems;
and then ussing templates I created functions for each derivative and I tried passing in the derivatives like so:
template <>
void Array::addToMap<Number>(Number input)
{
numberVariables[itemCount_] = input;
itemCount_++;
}
By doing so this function was not called because everything was of type Variable of course and I found out about slicing.
So instead I changed my map to take in pointers to my base class
std::map<int, Variable*> varriableItems;
but the problem I have is that all my objects are not created as pointers so I could not pass them in and I was getting errors.
No suitable conversion from "Number" to "Variable" exists.
Due to my implementation I can only create instances of objects
like so:
auto aNumberVariable = Number{50};
Ofcourse if I instead do:
Number aNumberVariable = new Number(50);
it works great.
The reason am doing this is explained bellow.
Please bear with me because this is a weird assignment.
We were asked to create a program that behaves/understands the syntax of a programming language called Logo, without actually analyzing the text as an input file, but rather "disguise" it to appear as such while in fact we just use C++ using what we learned from C++ and lots of overloads and pre-processor tricks
We have to be able to make our own "types" of variables called NUMBER,WORD,BOOLEAN,ARRAY, LIST,SENTENCE.
To declare them we have to use(note no semi-colons should be used):
//define number variable with value 21
MAKE number = NUMBER: 21
//define hello variable with value “hello”
MAKE hello = WORD: “hello”
//define myMoves variable contains list of turtle moves
MAKE myMoves = LIST [
LIST [WORD: “FORWARD”, NUMBER: 100],
LIST [WORD: “LEFT”, NUMBER: 90],
LIST [WORD: “FORWARD”, NUMBER: 100]
]
//define array variable with empty array
MAKE array = ARRAY {
number,
hello,
NUMBER: 12
BOOLEAN: TRUE,
ARRAY {
myMoves,
LIST [WORD: “BACK”, NUMBER: 100]
}
}
//define book variable with sentence type
MAKE book = SENTENCE (hello, WORD: “hello!”)
That's just a small part, we later have to support functions, nested loops , etc.
So do this I have to find a way to use the colon since I cannot overload it, so I did this:
//Create an instance of Number and write the first half of the ternary operator so we
//always get the false value so we can use the : like this
#define NUMBER Number{} = (false) ? 0
//semicolon infront for the previous command that needs it
#define MAKE ;auto
So now this:
//following commands will deal with the semicolon
MAKE myNumber = NUMBER: 21
worked great and it actually gets replaced by the processor to this:
auto myNumber = Number{} = (false) ? 0 : 21
So i worked with this for all my derivatives and I proceeded to overload operators to compare them, implement if else function in a similarly weird syntax.
Now I either have to figure out a way to make this work again but this time creating them as pointer instead (Which I assume is the only way for this to work, but I so far I couldn't figure it out) or create a single class for all types but doing it in separate objects that all inherit from a single base class makes more sense to me.
And am not sure how strict they will be, it is an unconventional project assignment for sure.
The reason I want to hold them together in a container is so I can then implement an Array and list object that can hold every type. At first I tried to use a different container for each type and made an iterator to iterate multiple maps separately, but when I got to the LIST implementation things got weird.
The list syntax is using the brackets [ ] which can only get 1 input value, so the idea was to collect them by overloading the comma operator and pass in one value to the list object.
I know this is weird , thank you for your time
I didn't read through all of your post. (actually I did because your task is so ... beyond words) but if you need polymorphism in a container and you also need the container to hold the objects, then the solution is unique_ptr:
container<std::unique_ptr<Base>>
In your case it would go something along this:
std::unordered_map<int, std::unique_ptr<Variable>> varriableItems;
varriableItems[0] = std::make_unique<Number>(50);
Related
Efficient way to declare and access a huge array
I am writing a code for which I need to declare an array of around 200 indexes. Now to search a specific index I at least need to travel the array for a defined time or until desired value is achieved - hence at times I might need to travel 200 times if needed - for 200 value row. This is exactly I wish to ignore so I landed coding it below way: enum Index{ salary, age }; static const Datas Mydata [] = { [Index::one] = {"hello", function_call_ptr_1, function_call_ptr_2}, [Index::two] = "hekllo1", function_call_ptr_1, function_call_ptr_2} }; Hence in my code I can directly seek it like below: Mydata [Index::age] Assuming that access to above structure is to be done inside a function - hence the function should receive Index value as argument to itself. But still what if arguments passed was wrong like: age = 0; fun(age); Is there a better way to access Mydata so that its desired row can easily be accessed without any flaw?
Assigning the Same Variable to Multiple struct Members with Different Values?
So far, I am trying to get my program to find the amount of bonds and element can have, provided by the user's input. I thought the easiest way of defining the same variable (bonds) across many different strings (name of the element) would be to create a struct and define the elements as members of that struct: #include <iostream> #include <string> using namespace std; struct element { int bonds; } Hydrogen, Helium, Lithium, Beryllium, Boron, Carbon, Nitrogen, Oxygen; int Hydrogen.bonds=1; int main() { string x; int ans; cout<<"Enter an element to find the amount of bonds it can have."; cin>>x; cout<<x" has "x.bonds" bonds."; return 0; }; Then, the program returns 1 with the errors: expected initializer before ‘.’ token int Hydrogen.bonds=1; and ‘std::string’ has no member named ‘bonds’ I am writing this program as I learn about C++, but I can't find an easier solution to this. I'm trying to basically list the elements, then define their bond counts (e.g. Hydrogen.bonds=1; Carbon.bonds=4; Nitrogen.bonds=3;). Is there a better way of doing this?
Your program won't compile because of two invalid lines int Hydrogen.bonds=1; This doesn't work because by starting with int the compiler expects a new variable; however, you provide an existing one, so it aborts. You should fix this by using a constructor or adding Hydrogen.bonds = 1 to main. The second troublesome line cout<<x" has "x.bonds" bonds."; This one causes issues because you're missing <<. Unfortunately, x is a string and won't refer to the Element you want it too. Instead, it will just print their input back. What you want to do is use a lookup table. I suggest looking into std::map. First you'd set its members. (something like: table[element_string] = element_properties) Then you can reference it easily with table[element_string] and it will return whatever you set it to. reference material for std::map cplusplus - http://www.cplusplus.com/reference/map/map/?kw=map
Yes, there is a better way. You are essentially making a lookup table between an element and the number of bonds. I would start by doing that first (a std::map would be an easy start). You just need to populate it either as a static or at the top of the main() function. The next problem is the output. Make sure you have enough operators (<<) in the right locations. I am on a mobile and can't really write up a solution for you, but that's how I would approach your initial problem description.
C++ passing by reference in constructor
So I am making a program in C++ and my main method has to construct an object that takes as a parameter a vector. This is my code: int main() { vector<Seller> *staff = new vector<Seller>; for (int i = 0; i < 50; i++) { staff->push_back(Seller(i)); } BookStore store(*staff); deque<Book> books; books = store.getBooks(); } So, these are some pretty simple Object-Oriented concepts I think. My goals are: First, initializing an empty vector of sellers. A Seller is an object that has a constructor: Seller(int i); And represents, of course, a seller. Then, I want to fill in the vector with actual Sellers. These are constructed in the for loop. Then, I want to create a Store, which takes as an argument the sellers that work there. Finally, I create a new deque called books, and I assign to it the value of books in the Store class. The initialisation of the Books deque is done in the constructor of the Store: Store::Store(vector<Seller> &sellers) { this->sellers = sellers; this->books = deque<Book> (100, "Harry Potter"); } So this is the code and I am wondering if I am making a mistake in the passing arguments to new constructors part. I am a bit confused when passing by reference so I am asking for a bit on help on that part. I have two main questions: 1) Are there any errors there, considering how I want to run my program? Consider also that in the rest of the main method (not included here) I constantly change the value of the books deque. 2) Is there any way to replace an element in a deque without having to erase and insert? Is there a built-in function replace? If not, is the below code going to work if I just want to replace a value in the deque? For example, if the deque is like that: 3 4 5 2 And it (an iterator) has value 2. Then I want the deque to become: 3 4 6 2 When doing: books.erase(it); books.insert(it, 6); Thanks for any tips or help!
OK, here a short analysis. Firstly, the unique real error I found: staff is defined as a pointer and is given a value with new but is never released. You should anyway avoid using raw pointers, so either create the object on the stack: vector<Seller> staff{}; or use a smart pointer auto staff = make_unique<vector<Seller>>{}; (you will then have to learn something about the ownership semantics, so as you still are a beginner I'd recommend the first solution). Then, notice how the line this->sellers = sellers; in Store::Store will make a copy of the sellers vector, which probably is not what you meant. If you wanted your store to reference the variable created on main(), you should redefine your Store as class Store { // ... vector<Seller>& sellers; //... }; and the constructor as Store::Store(vector<Seller> &sellers) : sellers{sellers} // reference member variables must be given a value before the body of the constructor begins { books = deque<Book> (100, "Harry Potter"); } For the same reason, your line books = store.getBooks(); will make a copy of the deque (but maybe in this case it was intended). Finally, C++ offers many container manipulating functions under the <algorithms> library. Take a look at the reference. But if you already have an iterator to the element you want to replace, you do not need such algorithms, just write: *it = 6;
Initialize a Matrix of Pairs in Constructor
I'm creating a boardgame (Tzaar if curious :D) in openGL and I need to initialize my logical board with the starting pieces in each place. In my Game classe I have the following variable: std::pair<char,int> logicBoard[17][9]; and want to initialize it in the constructor following somewhat this example: logicBoard[][] = { {(0,0),(0,0),(0,0),(0,0),('z',1),(0,0),(0,0),(0,0),(0,0)}, {(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)}, {(0,0),(0,0),('c',1),(0,0),('y',1),(0,0),('z',1),(0,0),(0,0)}, {(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)}, {('c',1),(0,0),('b',1),(0,0),('x',1),(0,0),('y',1),(0,0),('c',1)}, {(0,0),('b',1),(0,0),('a',1),(0,0),('x',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('a',1),(0,0),('z',1),(0,0),('a',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('c',1),(0,0),('c',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('x',1),(0,0),(0,0),(0,0),('a',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('z',1),(0,0),('z',1),(0,0),('b',1),(0,0)}, {('z',1),(0,0),('x',1),(0,0),('c',1),(0,0),('x',1),(0,0),('c',1)}, {(0,0),('y',1),(0,0),('a',1),(0,0),('x',1),(0,0),('y',1),(0,0)}, {('z',1),(0,0),('b',1),(0,0),('a',1),(0,0),('y',1),(0,0),('z',1)}, {(0,0),('c',1),(0,0),('b',1),(0,0),('y',1),(0,0),('z',1),(0,0)}, {(0,0),(0,0),('c',1),(0,0),('b',1),(0,0),('z',1),(0,0),(0,0)}, {(0,0),(0,0),(0,0),('c',1),(0,0),('z',1),(0,0),(0,0),(0,0)}, {(0,0),(0,0),(0,0),(0,0),('c',1),(0,0),(0,0),(0,0),(0,0)} }; But since I'm not so in depth of C++, don't know the easiest way of doing so. Want it to be easily modified too since the board will be sent to Prolog (with the game logic) program through sockets, so it returns the modified board again to this variable.
Why not use a Container to better management of your pairs? It would be like this: std::vector< std::pair<char,int> > logicBoard; logicBoard.push_back({0, 1}); logicBoard.push_back({'c', 1}); And so on... This way if you ever need, lets say, the size of your "array" you can simply use logicBoard.size();
I would define a typedef, and here is a compilable snippet typedef std::pair<char,int> P; P logicBoard[17][9] = { {P(0,0),P(0,0),P(0,0),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P('c',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P(0,0)}, {P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)}, {P('c',1),P(0,0),P('b',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0),P('c',1)}, {P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('a',1),P(0,0),P('z',1),P(0,0),P('a',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('c',1),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('x',1),P(0,0),P(0,0),P(0,0),P('a',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('z',1),P(0,0),P('z',1),P(0,0),P('b',1),P(0,0)}, {P('z',1),P(0,0),P('x',1),P(0,0),P('c',1),P(0,0),P('x',1),P(0,0),P('c',1)}, {P(0,0),P('y',1),P(0,0),P('a',1),P(0,0),P('x',1),P(0,0),P('y',1),P(0,0)}, {P('z',1),P(0,0),P('b',1),P(0,0),P('a',1),P(0,0),P('y',1),P(0,0),P('z',1)}, {P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('y',1),P(0,0),P('z',1),P(0,0)}, {P(0,0),P(0,0),P('c',1),P(0,0),P('b',1),P(0,0),P('z',1),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P('z',1),P(0,0),P(0,0),P(0,0)}, {P(0,0),P(0,0),P(0,0),P(0,0),P('c',1),P(0,0),P(0,0),P(0,0),P(0,0)} }; BTW depending on your Prolog interface that should be adaptable to actually exchange values. In case, maybe you want to keep P lowercase.
How to make a variable name without creating an array in C++?
How do you make a variable name where you create a variable and then in brackets the variable number? (By the way, I'm just guessing out how the code should be so that you get what I'm trying to say.) For example: int var[5]; //create a variable var[5], but not var[4], var[3], var[2], etc. Then, the variable number must be able to be accessed by a variable value: int number = 5; int var[number]; //creates a var[5], not a var[4], etc. int var[2]; //creates a var[2], not a var[1], etc. cout >>var[number]; number = 2; cin << var[number]; If I'm way off track with my "example", please suggest something else. I need something similar to this for my game to operate, because I must be able to create an unlimited instance of bullets, but they will also be destroyed at one point.
It looks like you are looking for the functionality provided by std::map which is a container used to map keys to values. Documentation of std::map Example use In the below example we bind the value 123 to the integer key 4, and the value 321 to key 8. We then use a std::map<int,int>::const_iterator to iterate over the key/value pairs in our std::map named m. #include <map> ... std::map<int, int> m; m[4] = 123; m[8] = 321; for (std::map<int, int>::const_iterator cit = m.begin (); cit != m.end (); ++cit) std::cout << cit->first << " -> " << cit->second << std::endl; output: 4 -> 123 8 -> 321
It looks like you want variable length arrays, which is not something C++ supports. In most cases, the correct solution is to use an std::vector instead, as in int number = 42; // or whatever std::vector<int> var(number); You can use std::vector as you would use an array in most cases, and you gain a lot of bonus functionality.
If I understand what you want correctly (which I'm not certain that I do), you want to be able to create a place to hold objects and use them according to some index number, but to only create the specific objects which go in it on demand. You want do to this either because 1) you don't know how many objects you're going to create or 2) you aren't going to use every index number or 3) both. If (1) then you should probably just use a vector, which is an array-like structure which grows automatically as you add more things to it. Look up std::vector. If (2) then you could use an array of pointers and initially set all of the values to null and then use new to create the objects as needed. (Or you could use the solution recommend in part 3.) If (3) then you want to use some form of map or hash table. These structures will let you find things by number even when not all numbers are in use and will grow as needed. I would highly recommend a hash table, but in C++, there isn't one in the STL, so you have to build your own or find one in a third-party library. For ease, you can use std::map, which is part of the STL. It does basically the same thing, but is slower. Some C++ distributions also include std::hash_map. If it's available, that should be used instead because it will be faster than std::map.