So I have the main parent class called item and that class has 2 child classes called book and periodical. The ideas behind what I am trying to do is have a polymorphic array or a polymorphic vector that would be able to do something like this:
Now the example is in C# (but I want to do it in C++)
item [ ] items = new items [100];
items[0] = new book();
items[1] = new periodical();
for (int i = 0; i < items.size; i++ ) {
items[i].read();
}
Like I said, the small example code is in C# but I want to do this in C++ but I am not sure how to go about going it. I wanted to use arrays but I'm my research, I haven't found a clear way of how to accomplish this. I also thought if vectors were possible to use or this but I was not sure about that either.
Here is an example (if you have questions let me know):
#include <iostream>
#include <memory>
#include <vector>
class Item
{
public:
virtual ~Item() = default; // base classes with virtual methods must have a virtual destructor
virtual void read() = 0;
};
class Book final :
public Item
{
public:
void read() override
{
std::cout << "book read\n";
}
};
class Periodical final :
public Item
{
public:
void read() override
{
std::cout << "periodical read\n";
}
};
int main()
{
std::vector<std::unique_ptr<Item>> items;
// use emplace_back for temporaries
items.emplace_back(std::make_unique<Book>());
items.emplace_back(std::make_unique<Periodical>());
// range based for loop over unique_pointers in items
// use const& so item cannot be modified and & to avoid copy of unique_ptr (unique_ptr doesn't have a copy constructor)
for (const auto& item : items)
{
item->read();
}
return 0;
}
Related
I have a Singleton class that manages a container of Items, exposing public functions that allow Items to be added or removed from the container.
class Item;
typedef std::shared_ptr<Item> ItemPtr;
class Singleton
{
public:
static Singleton& Instance()
{
static std::unique_ptr<Singleton> Instance(new Singleton);
return *Instance;
}
void Add(ItemPtr item)
{
mContainer.push_back(item);
}
void Remove(ItemPtr item)
{
for (auto it = mContainer.begin(); it != mContainer.end(); it++)
if (*it == item)
mContainer.erase(it);
}
private:
std::vector<ItemPtr> mContainer;
};
I'd like Item to have the ability to add itself to the Singleton container via an Add() method, and remove itself from the container upon its destruction.
class Item
{
public:
Item() {}
~Item()
{
Singleton::Instance().Remove(ItemPtr(this));
}
void Add()
{
Singleton::Instance().Add(ItemPtr(this));
}
};
When I run the example below, I get a crash on Singleton::Remove(), specifically a EXC_BAD_ACCESS on mContainer.begin().
int main()
{
Item* a = new Item();
Item* b = new Item();
a->Add();
b->Add();
delete a;
delete b;
}
This seems to indicate that mContainer no longer exists. Looking at the call stack, I can also see one of the root call stack frames is the destructor Singleton::~Singleton(), which would explain why mContainer is no longer there.
I've tried a different approach : instead of using std::shared_ptr<Item> I simply used raw pointers (i.e., Item*) with the appropriate substitutions in the code. It worked without problems.
My questions are:
I guess what's happening is that the ownership of the Item objects is only released by the shared_ptr after the destruction of Singleton, which causes the error. Is this correct?
Is it impossible to do what I want to do if the container in Singleton is of shared_ptr<Item>?
If not, how could I do it?
The wisdom of doing this in the first place notwithstanding, what you want can be achieved if you're willing to use, and abide by the restrictions of, std::enabled_shared_from_this. See below:
#include <iostream>
#include <algorithm>
#include <memory>
#include <vector>
struct Item;
typedef std::shared_ptr<Item> ItemPtr;
class Singleton
{
private:
Singleton() {}
public:
static Singleton &Instance()
{
static Singleton s;
return s;
}
void Add(ItemPtr item)
{
mContainer.emplace_back(std::move(item));
}
void Remove(const ItemPtr& item)
{
mContainer.erase(
std::remove(mContainer.begin(), mContainer.end(), item),
mContainer.end());
}
void Clear()
{
mContainer.clear();
}
private:
std::vector<ItemPtr> mContainer;
};
// note derivation. this means you can get a std::shared_ptr<Item>
// via `shared_from_this` , but it also means the object itself
// MUST be an actual shared object to begin with.
struct Item : public std::enable_shared_from_this<Item>
{
void Add()
{
Singleton::Instance().Add(shared_from_this());
}
};
int main()
{
ItemPtr a = std::make_shared<Item>();
ItemPtr b = std::make_shared<Item>();
// add to the singleton container
a->Add();
b->Add();
// report reference count of 'a'
std::cout << "before removal 'a' has " << a.use_count() << " references\n";
Singleton::Instance().Remove(a);
std::cout << "after removal 'a' has " << a.use_count() << " references\n";
}
Output
before removal 'a' has 2 references
after removal 'a' has 1 references
The most important part of this is the creation of a and b in main . Notice they are, in fact, managed by std::shared_ptr enshrouding from inception. This is required for std::enable_shared_from_this to work correctly. The rest is fairly straight forward. The ability to get a reference-bumped std::shared_ptr from within the body of any member of Item is done via the shared_from_this() member provided from the base class std::enable_shared_from_this.
In short, taking this approach will work for you, but at no point can you use shared_from_this() unless the object it is being fired upon is already managed by a std::shared_ptr in the first place. Keep that in mind.
So what I'm trying to achieve here is casting a derived subclass into another subclass derived from the same subclass. This far it's looking like it's not possible to actually be done but I'm still believing.
My example code is:
#include <iostream>
#include <vector>
class BaseClass
{
public:
virtual void printFunction() = 0;
};
class printOne : public BaseClass
{
public:
void printFunction() override
{
std::cout << "One\n";
}
};
class printTwo : public BaseClass
{
public:
void printFunction() override
{
std::cout << "Two\n";
}
};
int main()
{
std::vector<BaseClass *> baseClassVector;
printOne * one = new printOne;
baseClassVector.push_back(one);
printTwo * two = new printTwo;
baseClassVector.push_back(two);
}
So what i want to actually do here with this vector is that I want to change the "one" object on index zero, to a "two" object. Now this can be done through the code
delete baseClassVector[0];
printTwo * two = new printTwo;
baseClassVector[0] = two;
However as far as I know, this is extremely costly, especially if it has to be done at runtime. I was wondering if there's another way to go about doing this or if the costs are worth it compared to other alternatives.
Thanks in advance!
With the simplified example in the question, use a std::variant which is simpler and just avoid the base class altogether:
class printOne
{
public:
void printFunction() const
{
std::cout << "One\n";
}
};
class printTwo
{
public:
void printFunction() const
{
std::cout << "Two\n";
}
};
using printEither = std::variant<printOne, printTwo>;
void printFunction(const printEither& e)
{
std::visit([](auto& p) { p.printFunction(); }, e);
}
int main()
{
std::vector<printEither> eitherVector;
printOne one;
eitherVector.push_back(one);
printTwo two;
eitherVector.push_back(two);
eitherVector[0] = two;
for (auto& e: eitherVector)
printFunction(e);
}
Re-using an allocation for effectively unrelated types in C++ is a pain to write correctly. It is easier and preferable to incur an allocation.
It is technically possible to "rebuild" an object in place as a different type, though the following should be taken as just a proof of concept, not a recommendation for design or practice. First price to pay is giving up the convenience of new/delete for manually managed placement new and explicit destructors used with malloc/free.
const size_t sz = max(sizeof(printOne), sizeof(printTwo));
BaseClass *either = (BaseClass *)malloc(sz); // allocate memory for objects
new(either) printOne(); // construct printOne object
printOne *one = dynamic_cast<printOne *>(either); // ... use printOne object
one->~printOne(); // destruct printOne object
new(either) printTwo(); // construct printTwo object
printTwo *two = dynamic_cast<printTwo *>(either); // ... use printTwo object
two->~printTwo(); // destruct printTwo object
free(either); // free memory used by objects
I'm coming from c#/Java/TypeScript. So do I initialise objects inside a class. For example for a chess game. Lets say I have class for the spot on the board, the board.
So normally it will be
public class Piece()
{
bool isWhite;
Piece(isWhite){
this.isWhite = true;
}
}
public class Spot(){
Piece piece //Chess Piece
Spot(bool isWhite)
{
this.piece.isWhite = isWhite;
}
}
As mentioned in the comment to your post https://cppreference.com/ is usually the best place to look up documentation.
Now about your question:
#include <iostream>
#include <vector>
class Piece
{
public:
~Piece() = default;
explicit Piece(bool isWhite)
{
this->isWhite = isWhite;
}
bool isWhite;
};
class Board
{
public:
Board() = default;
~Board() = default;
void addPiece(Piece p)
{
pieces.push_back(p);
}
std::vector<Piece> pieces;
};
int main()
{
Board b;
Piece p(true);
b.addPiece(p);
std::cout << "Hello World!\n";
return 0;
}
This is how you would usually define a class that has a member from another class.
You should definitely check out constructors and destructors in c++ as they are very important (https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm).
And as for vector, this is a generic container from the c++ standard library.
Edit: I did indeed forget to add the default keyword to the constructor and destructor of Board which are unnecessary. The reason I've left them there is to showcase their existence to someone new to the language.
Also the reason I didn't pass the piece be reference is because references and pointers might be a complete chapter for someone new to the language.
Basically, the optimal way to write:
void addPiece(Piece p)
{
pieces.push_back(p);
}
is:
void addPiece(const Piece& p)
{
pieces.push_back(p);
}
Hello I'm studying c++ language and I'm really wondering that if use object Pointer with dynamic array. Weapon class is derived by CItem class. At this time I'm typing like this.
CItem* pItem = new cWeapon[m_size];
and I doing initialize each object like this
pItem[0].initialize();
pItem[1].initialize();
pItem[2].initialize();
pItem[3].initialize();
....
pItem[n].initialize();
However this time make problem. Size is different pItem and cWeapon. Because Pointer Operation cause error.
and I wondering that how solve this problem?
sorry about my fool English skill.
Example code:
#include <iostream>
#include <memory>
#include <vector>
class BaseItem // abstract class
{
public:
virtual void initialize() = 0; // pure virtual function (no implementation)
};
class Sword : public BaseItem
{
public:
void initialize() override
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
class Shield : public BaseItem
{
public:
void initialize() override
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
};
int main()
{
std::vector<std::unique_ptr<BaseItem>> items;
items.emplace_back(new Sword);
items.emplace_back(new Sword);
items.emplace_back(new Shield);
items.emplace_back(new Sword);
items.emplace_back(new Shield);
for(auto& element : items)
{
element->initialize();
}
return 0;
}
You can run it here: wandbox.org
Output:
virtual void Sword::initialize()
virtual void Sword::initialize()
virtual void Shield::initialize()
virtual void Sword::initialize()
virtual void Shield::initialize()
In this implementation I used std::vector for dynamic arrays. Vector is containing types of smart pointer to BaseItem. In this case smart pointer is std::unique_ptr it helps a lot with resource management and it is easy to use. Without it you need manually delete all elements from vector. I really recomend using it.
Our BaseItem now can provide "interface" that we want to implement in any other class. If you don't want to force class to implement such method just don't make it pure virtual (remove = 0 and add {} body of function)
More information about:
C++ Abstract Class
__PRETTY_FUNCTION__
C++ virtual functions
C++ inheritance
This is kind of "old" approach. You can read also about composition and entity system (ES).
I have a large class with many methods. This class has a subclass that manages a different situation.
Just to clear it up with an example the actual situation is the following:
class Logic {
public:
virtual void method()
{
Something::getInstance()->doSomething();
}
};
class ArrayLogic : public Logic {
private:
Something** array;
public:
void method() override
{
for (int i = 0; i < AMOUNT; ++i)
array[i]->doSomething();
}
};
Now this pattern repeats itself in multiple methods and I'd like to have just one implementation without trading for performance (since some of this methods are actually already proven to require efficiency).
I was thinking if it's possible with C++11 to have a template solution approach which is able to manage this situation at compile time without the necessity to duplicate the code.
Mind that the array doesn't make sense to exist for Logic so having a Something*[1] is not a viable option.
An additional problem is that at the moment Something** array is not directly contained in ArrayLogic but resides in another class, so it's more like
class ArrayLogic : public Logic {
private:
Container* container;
public:
void method() override {
for (int i = 0; i < AMOUNT; ++i)
if (container->array[i])
container->array[i]->doSomething();
}
}
While having to check for container->array[i] != nullptr may seems strange the fact is that the position is relevant, so an element removed from the array doesn't cause a shift of the successive element but leaves a hole.
I'd try and create separate classes for single and multiplayer games. Base both of these on a base class LogicBase that has a method(Something*) function that calls doSomething() on its parameter. This is what #Pradhan was referring to.
In your main game, you can use a LogicBase* to refer to either a SinglePlayerLogic or a MultiPlayerLogic object and call the relevant method() using a virtual function call.
I'm passing what is stored in Container to the constructor of MultiPlayerLogic. But it could be in a separate class and accessed that way. Similarly, it may be cleaner to pass a Something to the constructor of SinglePlayerLogic, but I wanted to keep the code structure close to your original, so didn't do this.
It initially looks funny for LogicBase to call to a subclass, then have those subclasses call the protected method(Something*) back in the super class. I've seen it elsewhere as a design pattern, but can't recall it's name.
#include <iostream>
#include <vector>
const int AMOUNT = 5;
struct Something {
void doSomething() { std::cout << "Something::doSomething\n"; }
static Something* getInstance() { static Something s; return &s; }
};
class LogicBase {
public:
virtual void method() = 0;
protected:
void method(Something* s) { s->doSomething(); }
};
class SinglePlayerLogic : public LogicBase {
public:
void method() override
{
std::cout << "SinglePlayer::method\n";
LogicBase::method(Something::getInstance());
}
};
class MultiPlayerLogic : public LogicBase {
public:
MultiPlayerLogic(Something **s) : players(s) {}
void method() override
{
std::cout << "MultiPlayer::method\n";
for (int i = 0; i < AMOUNT; ++i) {
if (players[i] == nullptr) {
continue;
}
std::cout << i << " ";
LogicBase::method(players[i]);
}
}
private:
Something** players;
};
int main() {
LogicBase* lb;
SinglePlayerLogic spl;
lb = &spl;
lb->method();
std::vector<Something*> players{AMOUNT};
MultiPlayerLogic mpl(players.data());
lb = &mpl;
lb->method();
}