Adding subClasses to BaseClass vector C++ doesn't work [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
i have the following problem, i have 2 Classes FooClass and BaseClass, and multiple SubClasses of BaseClass.
I want to add these various Subclasses into the same Vector in FooClass, because i am just implementing functions from baseclass, so i can access them through the vector key.
In the following example, each subclass sets the string name of the BaseClass with setName(), and returns it with getName().
Every subclass uses also thisFunctionisforAll() defined in the BaseClass.
The code does compile fine, except if i add vClasses.push_back(thesubclass);
So i need help how i can put all these subclasses of BaseClass into the same vector.
I want to iterate through the varius subClasses of BaseClass in the FooClass vector to output their names.
Example is in main.cpp
I thought i can add different subclasses to a vector if i they share the baseclass and the vector is type of the baseclass.
Here is the source:
FooClass.h:
#ifndef TESTPROJECT_FOOCLASS_H
#define TESTPROJECT_FOOCLASS_H
#include <vector>
#include "BaseClass.h"
using namespace std;
class FooClass
{
private:
vector<BaseClass> vClasses;
public:
void addClassToVector(BaseClass &classToAdd);
void getNames();
};
#endif //TESTPROJECT_FOOCLASS_H
FooClass.cpp
#include "FooClass.h"
void FooClass::addClassToVector(BaseClass &thesubclass)
{
vClasses.push_back(thesubclass);
}
void FooClass::getNames()
{
for (size_t i; i < vClasses.size(); i++)
{
cout << vClasses[i].getName() << endl;
}
}
BaseClass.h
#ifndef TESTPROJECT_BASECLASS_H
#define TESTPROJECT_BASECLASS_H
#include <iostream>
using namespace std;
class BaseClass
{
protected:
string name;
public:
virtual void setName()= 0;
virtual string getName()=0;
void thisFunctionisforAll();
};
#endif //TESTPROJECT_BASECLASS_H
BaseClass.cpp
#include "BaseClass.h"
void BaseClass::thisFunctionisforAll() {
cout << "Every subclass uses me without implementing me" << endl;
}
SubClass.h
#ifndef TESTPROJECT_SUBCLASS_H
#define TESTPROJECT_SUBCLASS_H
#include "BaseClass.h"
class SubClass : public BaseClass {
virtual void setName();
virtual string getName();
};
#endif //TESTPROJECT_SUBCLASS_H
SubClass.cpp
#include "SubClass.h"
void SubClass::setName()
{
BaseClass::name = "Class1";
}
string SubClass::getName() {
return BaseClass::name;
}
SubClass2.h
#ifndef TESTPROJECT_SUBCLASS2_H
#define TESTPROJECT_SUBCLASS2_H
#include "BaseClass.h"
class SubClass2 : public BaseClass
{
virtual void setName();
virtual string getName();
};
#endif //TESTPROJECT_SUBCLASS2_H
SubClass2.cpp
#include "SubClass2.h"
void SubClass2::setName()
{
BaseClass::name = "Class 2";
}
string SubClass2::getName() {
return BaseClass::name;
}
main.cpp
#include "FooClass.h"
void FooClass::addClassToVector(BaseClass &thesubclass)
{
vClasses.push_back(thesubclass);
}
void FooClass::getNames()
{
for (size_t i; i < vClasses.size(); i++)
{
cout << vClasses[i].getName() << endl;
}
}
I think the solution will be simple, but i am experienced in PHP and there i hadn't such issues.

You need to use pointers or references. Polymorphism only works in C++ when you're using pointers. You cannot treat a subclass as a superclass unless you're using pointers or references. You'd need std::vector<BaseClass*> to be able to have a container of both the base class and subclass.
Since you're new to the language, I would recommend researching how pointers work.

Containers like vectors contain things directly, not references to things (as found in, e.g., Java - not sure about PHP). If you've got a class Foo then a std::vector<Foo> will contain Foo instances. If there's a class Bar that derives from Foo and you put a Bar into this vector you'll only get the Foo part of it. The rest is cut off, or sliced, as described here: C++ - What is object slicing?. This is the way it works in C++.
Now, you can put pointers into the vector, e.g., a vector<Foo*>. But the vector object won't own the things pointed to (as it would in a language like Java, for example). It'll just be holding pointers. So you have to manage object lifetime separately. This is a main feature of C++. If you want the vector to own the objects you've got to put your pointers in there as a specific type of wrapped pointer, usually std::unique_ptr or std::shared_ptr.
But now you're getting into more complex but absolutely fundamental C++ stuff and you'll need to understand a lot about how ownership and containers work. Still, there are plenty of ways to learn that, I'm sure you know, and Stack Overflow's c++ tag will have a lot of questions on those topics with useful answers for you.

Related

c++ forward declaration + ifndef also needs pointers [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Array:
#ifndef ARRAY_H
#define ARRAY_H
#include <bits/stdc++.h>
using namespace std;
namespace Maifee{
class Value;
class Array {
public:
Array();
vector<Value> _elements;
};
}
#endif // ARRAY_H
Object :
#ifndef OBJECT_H
#define OBJECT_H
#include <bits/stdc++.h>
#include "value.h"
using namespace std;
namespace Maifee{
class Value;
class Object{
public:
Object();
map<string, Value> _members;
};
}
#endif // OBJECT_H
Value :
#ifndef VALUE_H
#define VALUE_H
#include <bits/stdc++.h>
#include "array.h"
#include "object.h"
using namespace std;
namespace Maifee{
class Array;
class Object;
class Value {
public:
Value();
Value(Object *__object);
Array *_array;
Object *_object;
};
}
#endif // VALUE_H
I'm learning C++ at my best. With my teeny tiny knowledge in C++, I am trying to write some code. First reason I'm moving C++, pointers take a lot's of time.
Here I'm writing these code, where forward-declaration is necessary, and due to this even after using forward-declaration and ifndef, I need to use pointer, which I really don't want.
Can anyone really help me with this, how can I remove circular dependency??
Do I need to go back to C?
When using pointer I faced many problems such as, I have just one key-value pair in my map, but in the next line size becomes a very large number, out of nowhere.
Code inside main :
Object object=Object();
cout << "pop obj tem len" << object._members.size() << endl; //gives 0 as expected
object._members = members;
cout << "pop obj tem len" << object._members.size() << endl; //gives the expected number
Value val=Value(&object);
cout << val._object->_members.size() << "size here" << endl; //gives a random number
Constructor for Value with Object parameter :
Value::Value(Object *__object)
{
Object object;
object._members.insert(__object->_members.begin(), __object->_members.end());
_object = &object;
}
You can't avoid the forward-declarations and pointers in this situation.
class Object has a map<string, Value> member, and class Array has a vector<Value> member. Which means Value must be a fully-defined, complete type by the time Object and Array are being compiled, as map and vector need to know the total size of their element types. If Value were to have non-pointer Array and Object members, then Object and Array would need Value to be a complete type, but Value would need Object and Array to be complete types. Catch-22!
So, you have to use forward declarations and pointers/references for the Value members in order to make this kind of circular referencing work properly, since pointers/references to incomplete types are allowed.
UPDATE: In your Value constructor that takes an Object* parameter, you are setting the _object member to point at a local Object instance that goes out of scope and is destroyed when the constructor exits, thus leaving _object dangling. That is why the subsequent val._object->_members.size() expression in main() produces garbage (you are lucky the code didn't crash outright) - val._object is pointing at invalid memory, so its members is not a valid map object and so reading its size() is undefined behavior. That goes right back to the original comment I posted:
You are likely accessing an invalid pointer.
To solve this, depending on your actual design goal, the Value constructor needs to either:
construct a new Object dynamically, which will have to be delete'd later. You will also have to provide a proper copy constructor and copy assignment operator:
Value::Value()
{
_object = NULL;
_array = NULL;
}
Value::Value(Object *__object)
{
_object = new Object;
_array = NULL;
if (__object)
_object._members = __object->_members;
}
Value::Value(const Value &__value)
{
_object = new Object;
_array = NULL;
if (__value._object)
_object._members = __value._object->_members;
}
Value::~Value()
{
delete _object;
}
Value& Value::operator=(const Value &__value)
{
if (&__value != this)
{
Value tmp(__value);
std::swap(_object, tmp._object);
std::swap(_array, tmp._array);
}
return *this;
}
simply store the Object* pointer it is given:
Value::Value(Object *__object)
{
_object = __object;
_array = NULL;
}

Making a vector of superclass type that can store subclass objects

So I started a small little project to work on while I am learning. Basically, what I'm trying to do is a small "game" which I plan to build on as I learn new things.
Here is a brief description and my problem.
Basically, I want to assign various Hero types to a player based on their choice.
I made a base class "Hero" with only a HP parameter so far. After that, I made 2 derived classes from Hero, HeroType1, HeroType2 which will have specific abilities and so on.
I decided on storing various hero types in std::vector<Hero*> Heroes. Basically, I start my "game" by calling initializeHeroes function which, depending on the player choice creates a new object of type NewHero1 or NewHero2 and stores it an the vector mentioned before. The thing is, no matter what I tried so far, I can't access derived member functions when I want to use them later, only those of the Hero class.
What feels like a good solution: declare global variables player1, player2 and assign to them after players choose the HeroType. However, I can't do that because the data type has to be known before compiling. Sorry if this is a stupid and basic question, my knowledge is still very limited and that is why I am asking for some hints here.
I'd kindly like to ask on how would you approach this, I know it is a very simple issue, but I'm still a beginner and I'm trying to figure out the best way to solve this. Thanks in advance.
If you would like to call a member function from a element from std::vector<Hero*> Heroes and you know somehow that this element points to a Hero2-type, then you could create a new temporary variable Hero2 * tmpPtr and set this variable to the element whose memberfunction you want to call (tmpPtr = Heroes[i]). Then you should be able to call a memberfunction like this: tmpPtr->hero2Memberfuncion().
Full code:
#include <iostream>
#include <vector>
class SomeClass
{
public:
void a() {
std::cout << "a" << std::endl;
}
};
class AnotherClass : public SomeClass
{
public:
void b() {
std::cout << "b" << std::endl;
}
};
void main() {
std::vector<SomeClass *> vec;
AnotherClass v;
vec.push_back(&v);
AnotherClass * tmpPtr = (AnotherClass *)vec[0];
tmpPtr->b(); //Output: "b"
}
However if you want for example loop through the whole vector and for every element run a memberfunction that has the same name but the body of that function differs depending on to what Hero-type the element points, then you may want to use virtual functions. Example:
#include <iostream>
#include <vector>
class SomeClass
{
public:
virtual void a() {
std::cout << "from SomeClass" << std::endl;
}
};
class AnotherClass : public SomeClass
{
public:
void a() {
std::cout << "from AnotherClass" << std::endl;
}
};
void main() {
std::vector<SomeClass *> vec;
AnotherClass v1;
vec.push_back(&v1);
vec[0]->a(); //Output: "from AnotherClass"
SomeClass v2;
vec.push_back(&v2);
vec[1]->a(); //Output: "from SomeClass"
}

Filing a vector outside of a function in a class

Fairly simple question here, whats the best way to fill a vector outside of a function in a class .cpp file? currently i'm attempting the following which is not working:
std::vector<Player> midfielder(8);
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
To provide context, 'Midfielder' is a class that inherits from the 'Player' class.
TeamManagment.h
#ifndef TEAMMANAGEMENT_H
#define TEAMMANAGEMENT_H
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include <string>
class TeamManagement
{
public:
TeamManagement();
void Display_Players();
};
#endif // TEAMMANAGEMENT_H
TeamManagement.cpp
#include <iostream>
#include <string>
#include <vector>
#include "Player.h"
#include "Midfielder.h"
#include "TeamManagement.h"
using namespace std;
TeamManagement::TeamManagement()
{
}
std::vector<Player> midfielder(8);
//errors start occurring on line below: 'midfielder' does not name a type
midfielder.at(0) = Midfielder("Default ",0,"Midfielder");
midfielder.at(1) = Midfielder("David Armitage ",1,"Midfielder");
midfielder.at(2) = Midfielder("Tom Rockliff ",2,"Midfielder");
midfielder.at(3) = Midfielder("Gary Ablett ",3,"Midfielder");
midfielder.at(4) = Midfielder("Dyson Heppel ",4,"Midfielder");
midfielder.at(5) = Midfielder("Scott Pendlebury",5,"Midfielder");
midfielder.at(6) = Midfielder("Michael Barlow ",6,"Midfielder");
midfielder.at(7) = Midfielder("Jack Steven ",7,"Midfielder");
//errors stop occurring here
void TeamManagement::Display_Players(){
cout<<"Position Name ID"<<endl;
for (int i=1;i<8;i++)
{
cout<<midfielder[i].Player_Details()<<" "<<midfielder[i].Get_player_id()<<endl;
}
}
The first problem is that you cannot perform assignment like that outside of a function. You must use construction or initialization.
With C++98 you cannot populate/initialize a vector outside of a function.
With C++11/14 you can populate one using initializer syntax:
#include <iostream>
#include <vector>
struct Thing {
int m_i, m_j;
Thing(int i, int j) : m_i(i), m_j(j) {}
};
std::vector<Thing> things {
{ 1, 2 }, { 2, 3 }
};
int main() {
std::cout << "things[0].m_j = " << things[0].m_j << '\n';
}
But std::vector won't like you trying to put "Midfielder"s into a vector of Player. Lets use an SSCCE to reconstruct the damage you're doing:
#include <iostream>
struct Base {
int i;
};
struct Derived : public Base {
int j;
};
int main() {
std::cout << "Base size = " << sizeof(Base) << '\n';
std::cout << "Derived size = " << sizeof(Derived) << '\n';
}
This tells us that Base and Derived have a different size. But you're trying to put these two objects into the same container because they're related. Round peg and square peg are related... They won't fit into the same hole, and this is the problem we have now.
The vector creates space in memory for your elements based on the type you supply, and then it requires you to pass it exactly that type to populate those spaces with, or a type that has a conversion mechanism to the storage type.
If you want to have a container of different types, you'll need to use pointers, but then you're going to run into the problem that what you get back will be a pointer to the base type and you will need to provide yourself with a way to distinguish different player types.
See Store derived class objects in base class variables for the C++98 approach. In modern C++ (11 and 14) you should use smart pointers, e.g.
std::vector<std::unique_ptr<Base>>
std::vector<std::shared_ptr<Base>>
Presumably default constructing a Midfielder doesn't make a lot of sense, so you can reserve the memory, then emplace_back into the vector.
std::vector<Player> midfielder {};
midfielder.reserve(8);
midfielder.emplace_back("Default ",0,"Midfielder");
midfielder.emplace_back("David Armitage ",1,"Midfielder");
midfielder.emplace_back("Tom Rockliff ",2,"Midfielder");
midfielder.emplace_back("Gary Ablett ",3,"Midfielder");
midfielder.emplace_back("Dyson Heppel ",4,"Midfielder");
midfielder.emplace_back("Scott Pendlebury",5,"Midfielder");
midfielder.emplace_back("Michael Barlow ",6,"Midfielder");
midfielder.emplace_back("Jack Steven ",7,"Midfielder");
midfielder.at(0) = Midfielder("Default ",0,"Midfielder"); is a statement. You've put that and similar statements in (global) namespace scope. That's your bug. Only declarations may be in namespace scope. You must put your statements inside a function.
The error message stems from the fact that declarations which don't start with a keyword start with a type name. Since midfielder is not a keyword, the compiler expects it to be a type name but it isn't one, so you get the error.

How do I point at a vector in another class?

I have a class that holds a vector, which also inherits another class:
class txtExt : public extention
{
private:
string openedFile_;
public:
vector<string> txtVector; //the vector i want to call
};
I fill the vector in a method within a class:
class Manager : public extention
{
// there is some other code here that I know does work
// and it calls this function:
void organizeExtention(string filename, string ext)
{
if(ext == "txt")
{
txtExt txtExt;
txtExt.txtVector.pushback(filename);
}
}
}
and this is my main class where i attempt to call the vector:
int main()
{
// some code here that does previous operations like getting the path
// and filling the vector
// I've tried many ways of trying to call the vector
// here is an example of one:
vector<txtExt*> testVector;
for(int i = 0; i < testVector.size(); ++i)
{
cout << testVector[i] << endl;
}
return 0;
}
I have a few questions:
Am I calling the vector wrong?
Is my vector empty?
Do I have to make my vector global, so other classes can see it?
Note: I've been able to print out the vector where I load the vector using a very simple for loop
Well, as has been said you have a few errors in the code posted, and you maybe have some misunderstandings as well. But to answer the question asked, this
testVector[i]->txtVector
is the way to access the txtVector object that is inside each of your txtExt objects.
If that doesn't work for you then it's because one of the other errors/misunderstandings you have in your code.
To summarize:
reread the first chapters of a good C++ book ( The Definitive C++ Book Guide and List ), then try try to fix your program and deal with each error one at the time.
There are several errors in your code.
First of all, there's no operator << for printing entities of the type txtExt*.
Even object of type txtExt is not printable just like that.
In addition, the testVector you made is empty, so no .size() will be zero, and there's going to be no looping.
Are you really sure that you like to inherit both your classes from 'extension' ?
You can't call a vector, you can access it.
Having a data member (like the vector) public is not a good idea.
Calling a variable by the same name as a class is a very bad idea.
I have trouble guessing what your code should do. Here's a simple example of things you need to understand:
#include <iostream>
#include <vector>
#include <string>
class TxtExt
{
public:
std::vector<std::string> txtVector;
};
int main(){
TxtExt oneTxtExt;
oneTxtExt.txtVector.push_back("hello");
oneTxtExt.txtVector.push_back("world");
for( auto &i : oneTxtExt.txtVector ){
std::cout << i <<std::endl;
}
}
The following code is correct, but has absolutely no effect. You could as well just write {}:
{
TxtExt TxtExt;
TxtExt.txtVector.pushback(filename);
}
You here create a new object, push back to it (btw it is called push_back), but then the object is destroyed at the end of the scope. Also, don't name you objects the same as the class, it becomes really confusing.

Need help with map (c++, STL)

Actually I'm new to C++. I tried something out (actually the map container) but it doesn't work the way I assumed it will... Before posting my code, I will explain it shortly.
I created 3 classes:
ClassA
ClassDerivedA
ClassAnotherDerivedA
The two last ones are derived from "ClassA".
Further I created a map:
map<string,ClassA> test_map;
I put some objects (from Type ClassDerivedA and ClassAnotherDerivedA) into the map. Keep in mind: the mapped value is from type "ClassA". This will only work because of Polymorphism. Finally I created an iterator which runs over my map and compares the user input with my keys in the map. If they match, it will call a specific method called "printOutput".
And there is the Problem:
Although i declared "printOutput" as "virtual" the only method called is the one from my base class, but why?
and here is the code:
#include <iostream>
#include <map>
using namespace std;
class ClassA
{
public:
virtual void printOutput() { cout << "ClassA" << endl; }
};
class ClassDerivedA : public ClassA
{
public:
void printOutput() { cout << "ClassDerivedA" << endl; }
};
class ClassAnotherDerivedA: public ClassA
{
public:
void printOutput() { cout << "ClassAnotherDerivedA" << endl; }
};
int main()
{
ClassDerivedA class_derived_a;
ClassAnotherDerivedA class_another_a;
map<string,ClassA> test_map;
test_map.insert(pair<string,ClassA>("deriveda", class_derived_a));
test_map.insert(pair<string,ClassA>("anothera", class_another_a));
string s;
while( cin >> s )
{
if( s != "quit" )
{
map<string,ClassA>::iterator it = test_map.find(s);
if(it != test_map.end())
it->second.printOutput();
}
else
break;
}
}
The problem is slicing. You are storing ClassA values in your map. When you store derived class instances into the map, the get sliced into ClassA objects. You'll need to store pointers in your map instead of values.
See this for more info on slicing: What is object slicing?
C++ is not Java. You cannot store a derived type in a variable of a base type. For example:
Base b = Derived();
will only store the Base part of Derived in the variable b. In order to get polymorphic behaviour, you would need to use pointers, and create the derived class dynamically:
Base * b = new Derived();
The same goes for C++ containers - you need:
map <string, Base *> m;
All of this should be covered in every introductory C++ text book - which one are you using?
You are experiencing "slicing". To get the virtual functions to work properly, you need to call them using a pointer or a reference. In other words, your map should contain pointers to ClassA:
map<string, ClassA *> test_map
Please remember to delete them when you are done, or use smart pointers.
Here's more on slicing: here, here, and here