I started programming in C++ after a 1-year break, and I am having difficulties here and there (not that I really knew it before the break).
My current problem is that I don't know how to use pointers properly.
I have the following std::vector:
std::vector<std::shared_ptr<IHittable>> world;
Where IHittable is the interface of Hittable objects.
Now, in this std::vector, multiple derivations of IHittable are pushed, like Sphere, Triangle, etc.
Each of these derived classes has a function intersects() like this:
Intersection Sphere::intersects(const Ray & ray)
{
auto x = ...
...
return {x, this};
}
Intersection looks like this:
class Intersection
{
public:
Intersection(double t, IHittable * object);
[[nodiscard]] double t() const;
[[nodiscard]] IHittable * object() const;
private:
double t_;
IHittable * object_ = nullptr;
};
I really don't know how to write this code correctly.
I need to return a this pointer from the member function intersects() of an object which is itself allocated dynamically and is stored in a std::shared_ptr.
Is there a way to handle this?
Another example:
std::vector<std::shared_ptr<IHittable>> world;
world.push_back(std::make_shared<Sphere>());
auto s = Intersection(4.0, world[0]);
Should work.
PS: I could just create multiple std::vectors without std::shared_ptr:
std::vector<Sphere> spheres;
std::vector<Triangles> spheres;
...
But IMHO, it would be nice to iterate over every object at once.
PS2: I am now using shared_from_this() and most of my code works, thanks.
I think this sounds like a good fit for std::enable_shared_from_this as Remy pointed out in the comments.
I whipped up a simplified example which hopefully makes it clear how it can be used to achieve what you're after.
class Intersection;
class IHittable : public std::enable_shared_from_this<IHittable> {
public:
virtual Intersection intersects( ) = 0;
virtual void print( ) const = 0;
virtual ~IHittable( ) = default;
};
class Intersection {
public:
Intersection( std::shared_ptr<IHittable> object )
: object_{ std::move( object ) }
{ }
void print_shape( ) const {
object_->print( );
}
private:
std::shared_ptr<IHittable> object_;
};
class Square : public IHittable {
public:
Intersection intersects( ) override {
return Intersection{ shared_from_this( ) };
}
void print( ) const override {
std::cout << "Square\n";
}
};
int main( ) {
std::vector<std::shared_ptr<IHittable>> objects{
std::make_shared<Square>( ) };
const auto intersect{ objects.front( )->intersects( ) };
intersect.print_shape( );
}
Related
So I am pretty new to C++ and am trying to understand smart pointers and the RAII design pattern. My question is this: say I have an object that contains a map of objects. I want one object at a time to be active, that is a want a pointer that points to one of the objects from the map. What is a proper RAII way to go about it using smart pointers? Below is what I have tried so far.
//StateMachine.h
std::unique_ptr<GameObject> p1Paddle = std::make_unique<GameObject>(Paddle());
std::unique_ptr<GameObject> p2Paddle = std::make_unique<GameObject>(Paddle());
std::unique_ptr<GameObject> ball = std::make_unique<GameObject>(Ball());
//StateMachine.cpp
StateMachine::StateMachine()
{
gameObjects["p1Paddle"] = std::pair <bool, std::unique_ptr<GameObject>>(false, std::move(p1Paddle));
gameObjects["p2Paddle"] = std::pair <bool, std::unique_ptr<GameObject>>(false, std::move(p2Paddle));
gameObjects["ball"] = std::pair <bool, std::unique_ptr<GameObject>>(false, std::move(ball));
}
void StateMachine::ChangeState(std::string key)
{
activeObject = std::move(gameObjects[key]);
}
Instead of using map and smart-pointer and based on your requirements that you only want a single object type at a given moment of time, perhaps you want a priority queue based implementation instead...
Here's a pseudo implementation:
#include <algorithm>
#include <cstdint>
#include <queue>
#include <string>
#include <vector>
enum class ComponentType {
PADDLE,
BALL
};
class Component {
protected:
ComponentType type_;
uint32_t id_;
priority_;
Component(ComponentType type, uint32_t id, float priority)
: type_{type}, id_{id}, priority_{prioity};
public:
virtual ~Component() {}
auto type() const { return type_; }
auto id() const { return id_; }
auto priority() const { return priority_; }
void updatePriority(float newPriority) { priority_ = newPriority; }
};
class Paddle : public Component {
private:
std::string name_;
public:
Paddle(std::string_view name, float priority) :
Component(ComponetType::PADDLE, std::stoi(name.data()), priority),
name_{name}
{}
auto name() const { return name_; }
};
class Ball : public Component {
private:
std::string name_;
public:
Ball(std::string_view name, float priority) :
Component(ComponentType::BALL, std::stoi(name.data()), priority),
name_{name}
{}
auto name() const { return name_; }
};
class CmpFunc {
public:
int operator(){ const Component& a, const Component& b) {
return a.priority() > b.priority();
}
};
class Game {
private:
//std::vector<Component*> components_;
std::priority_queue<Component*, std::vector<Component*>, CmpFunc> priority_;
public:
void initialize() {
Paddle paddle1("paddle_1", 0.1f);
Paddle paddle2("paddle_2", 0.2f);
Ball ball("ball", 0.3f");
addComponent(&paddle1);
addComponent(&paddle2);
addComponent(&ball);
}
void addComponent(Component* component) {
if (component == nullptr)
throw std::runtime_exception( "invalid component pointer!" );
//components_.push_back(component);
priority_.push(component);
}
auto getComponent() {
if (!priority_.empty()) {
auto component = priority_.top();
priority_.pop();
/*components_.erase(
std::remove(components_.begin(), components_.end(), component),
components_.end()
);*/
return component;
}
return nullptr;
}
};
This is just a pseudo example code to show a priority queue... I didn't show any implementation of updating or changing the priority queue of an object, nor did I show, how to directly use it based on some state X of the game or finite-state-machine... That would be an exercise for you...
I can not say whether this code will compile and run since I typed it out right here and have not yet tested it hence the pseudo code. You can play around with it and try to get it to compile and from there expand it to fit your own needs...
Suppose I'm writing a 3D renderer in C++11, where I create materials and assign them to a model.
I'd like to be able to create materials using the Named Parameter Idiom, like this:
auto material = Material().color( 1, 0, 0 ).shininess( 200 );
I can then create a model like this:
auto model = Model( "path/to/model.obj", material );
I also want to be able to pass the material as an r-value:
auto model = Model( "path/to/model.obj", Material() );
In this simple use case, I can write my Model class like this:
class Model {
public:
Model() = default;
Model( const fs::path &path, const Material &material )
: mPath( path ), mMaterial( material ) {}
private:
fs::path mPath;
Material mMaterial;
};
Question
I want to make Material an abstract base class, so that I can create custom implementations for specific kinds of materials. This means that in my Model I must store a pointer (or even reference) to the material instead. But then I can no longer pass the material as an r-value.
I could choose to use a std::shared_ptr<Material> member variable instead, but then it becomes much harder to use the Named Parameter Idiom, because how would I construct the material in that case?
Does any of you have some good advice for me?
More Detailed Example Code
class Material {
public:
virtual ~Material() = default;
virtual void generateShader() = 0;
virtual void bindShader() = 0;
};
class BasicMaterial : public Material {
public:
BasicMaterial() = default;
BasicMaterial( const BasicMaterial &rhs ) = default;
static std::shared_ptr<BasicMaterial> create( const BasicMaterial &material ) {
return std::make_shared<BasicMaterial>( material );
}
void generateShader() override;
void bindShader() override;
BasicMaterial& color( float r, float g, float b ) {
mColor.set( r, g, b );
return *this;
}
private:
Color mColor;
};
class Model {
public:
Model() = default;
Model( const fs::path &path, ...what to use to pass Material?... )
: mPath( path ), mMaterial( material ) {}
private:
Material mMaterial; // Error! Can't use abstract base class as a member.
Material* mMaterial; // We don't own. What if Material is destroyed?
Material& mMaterial; // Same question. Worse: can't reassign.
std::shared_ptr<Material> mMaterial; // This? But how to construct?
};
// Can't say I like this syntax much. Feels wordy and inefficient.
std::shared_ptr<Material> material =
BasicMaterial::create( BasicMaterial().color( 1, 0, 0 ) );
auto model = Model( "path/to/model.obj",
BasicMaterial::create( BasicMaterial().color( 0, 1, 0 ) );
Another way would be to add a class MaterialHolder that would have the shared_ptr as a member.
// *** Not tested ***
class MaterialHolder
{
public:
template <typename T> T &create()
{
T *data = new T;
material.reset(data);
return *data;
}
private:
std::shared_ptr<Material> material;
};
Usage:
MaterialHolder x;
x.create<BasicMaterial>().color(1, 0, 0);
And you could make some variations like:
Having a NullMaterial to handle the case where createis not called.
Throw an exception if you try to use a material that was not created.
Rename MaterialHolder to MaterialFactory and use that class only for creation purpose (and have a function to move out the pointer).
Use unique_ptr instead.
Or you could also always write the code by hand:
auto m1 = std::make_shared<BasicMaterial>();
(*m1)
.color(1, 0, 0)
.shininess(200)
;
Actually, I think I have almost answered my own question in the detailed code example. The shared_ptr<Material> approach works well, apart from its construction. But I could write the following helper function to remedy that:
namespace render {
template<class T>
std::shared_ptr<T> create( const T& inst ) {
return std::make_shared<T>( inst );
}
}
And now I can create a material and model like this:
auto model = Model( "path/to/model.obj", create( BasicMaterial().color( 0, 0, 1 ) );
This is readable, clear and not too wordy.
Of course, I'd still love to hear other ideas or opinions.
This question already has answers here:
Why is virtual function not being called?
(6 answers)
Closed 9 years ago.
AoA,
I am making a console game of chess, But I am stuck at polymorphism, below is the classes and functions definitions
/* old Part
//Base Class
class Piece /*Parent class */
{
protected:
Position* pCoord;
std::string color;
char symbol;
public:
Piece(Position* Coord,std::string Color,char symbol);
Position GetCurrentPos();
std::string GetColor();
void SetColor(std::string color);
void Draw();
virtual bool SetPos(Position* newPos){MessageBox(NULL,L"Virtual Running",L"Error",MB_OK); return true;};
virtual ~Piece();
};
/* Inherited classes */
//Child classes
class Pawn: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Pawn(Position* Coord,std::string Color,char symbol);
~Pawn();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Child classes
class Bishops: public Piece
{
private:
std::vector<Position>* allowPos;
public:
Bishops(Position* Coord,std::string Color,char symbol);
~Bishops();
std::vector<Position>* GetThreatendFields();
bool isValidMove(Position* newPos);
bool SetPos(Position* newPos);
};
//Here is the implementation of child class function SetPos
bool Pawn::SetPos(Position* newPos)
{
bool isSet = false;
this->pCoord = new Position();
this->pCoord = newPos;
isSet = true;
MessageBox(NULL,L"Child function running",L"Yuhuu!",MB_OK);
return isSet;
}
class ChessBoard
{
private:
Position ptr; //dummy
int SelectedPiece;
vector<Piece> pPieceSet;
bool isSelected;
public:
ChessBoard();
~ChessBoard();
void ShowPieces(Player *p1,Player *p2);
void Draw();
void MouseActivity();
void Place(Piece& p);
};
//it just shows the peices acquired from player objects..dummy vector pointer
void ChessBoard::ShowPieces(Player* p1,Player* p2)
{
std::vector<Piece>* vPiece = p1->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
vPiece = p2->GetPieces();
for( int i=0;i<vPiece->size();i++ )
{
Piece& piece = vPiece->at(i);
Place(piece);
piece.Draw();
}
}
*/
/*new part
I did what you say
Player::std::vector<Piece*> *vPieceSet;
Player::Player(int turn)
{
this->turn = turn%2;
this->vPieceSet = new std::vector<Piece*>;
}
void Player::Initialize() //Initial and final ranges for position
{
//Initialization of pieces to their respective position
Position pos;
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
this->vPieceSet->push_back(pPiece);
}
//other classes same as above
}
It runs fine at initialzation function(stores all classes fine) but when use function to get the vector object
std::vector<Piece*>* Player::GetPieces()
{
std::vector<Piece*>* tPieces = this->vPieceSet;
return tPieces;
}
//In main.cpp
it doesnot return the vector object
Player p1(0),p2(1);
p1.Initialize();
p2.Initialize(); //initialization done perfectly while debugging
vector<Piece*> *obj = p1.GetPieces(); //returns garbage
Piece* pObj = obj->at(0); //garbage
cout<<pObj->GetColor(); // garbage
*/new part
Sounds like I have another problem!
When you use polymorphism, what you are really trying to do is instantiate an object of derived type and call the methods on that object through a pointer or reference to the base object.
class Foo
{
public:
virtual void DoIt () { cout << "Foo"; }
};
class Bar
:
public Foo
{
public:
void DoIt () { cout << "Bar"; }
};
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OUTPUT = "Bar"
Foo& fooRef = *foo;
fooRef.DoIt(); // OUTPUT = "Bar"
}
In order for this to work, you need to use either a pointer or a reference to the object. You can't make a copy of the object using a the base class. If you make a copy, you will slice the object.
int main()
{
Foo* foo = new Bar;
foo->DoIt(); // OK, output = "Bar"
Foo fooCopy = *foo; // OOPS! sliced Bar
fooCopy.DoIt(); // WRONG -- output = "Foo"
}
In your code, the Piece class is intended to be polymorphic, and in your ChessBoard class you have a vector of this class:
class ChessBoard
{
private:
vector<Piece> pPieceSet;
};
Since this is a vector of the Piece object itself, and not a pointer-to-Piece, anything you put in here will be sliced. You need to change pPieceSet to be a vector of pointers-to-Piece:
vector <Piece*> pPieceSet;
You have further problems in Initialize, which need to be refactored anyway. For one thing, you have another vector of Piece objects, and there are two problems here. First, it needs to be a vector of pointers, and second, why do you need another vector at all when there is already one associated with the ChessBoard? I didn't thouroughly examine your code so maybe you do need it, but this seems like an error. There should probably just be one collection of pieces, in the ChessBoard.
In your Initialize method:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(*pPiece);
There are a couple of problems. One, you are pushing back a sliced copy of the Piece, which will be fixed when you change your vector to store pointers. Second, if you just change this like so:
Piece *pPiece;
// ...
Pawn pPawn(&pos,"blue",'P');
pPiece = &pPawn;
vPieceSet.push_back(pPiece); // <-- not dereferencing
You will have a new problem because you'll be storing the pointer to a local (automatic) variable. Best is to do this:
Piece* pPiece = new Pawn (...);
// ...
vPieceSet.push_back (pPiece);
Please don't forget to delete everything you new. This is best handled by using smart pointers rather than raw pointers. In C++03 we have auto_ptr, but those can't go in a vector. Instead you'll need to use Boost or something else, or just store raw pointers. In C++11, we now have unique_ptr (preferred) and shared_ptr, which can go in to a vector.
In C++11, the best solution here is to have a vector declared as:
vector <unique_ptr <Piece> > pPieceSet;
...unless you have some compelling need to use shared_ptr instead.
As others have mentioned, it is a slicing issue, and the issue is created here:
class Player
{
private:
std::string pName;
std::vector<Piece> vPieceSet; // <-- This is your problem
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece>* GetPieces();
};
You are storing them in the vector as instances of Piece, which is slicing off the details of the piece (e.g. the Bishop implementation). You should modify it to something like:
class Player
{
private:
std::string pName;
std::vector<Piece*> vPieceSet; // or better, use a smart pointer wrapper
int turn;
public:
Player(int turn);
~Player();
void Initialize();
std::string GetName();
void SetName(std::string Name);
int GetTurn();
std::vector<Piece*> GetPieces(); // note this change as well
};
With your additional question/edit, you are getting another unrelated problem:
void Player::Initialize() //Initial and final ranges for position
{
Position pos; // position is declared inside the scope of Initialize
Piece *pPiece;
if( this->turn == 0 )
{
this->SetName("Player 1");
for( int i=8;i<16;i++ )
{
pos.SetPosition(i);
Pawn pPawn(&pos,"blue",'P'); // you are passing the address of position to the Pawn, and Pawn is within the scope of this loop
pPiece = &pPawn; // you are storing the address of the Pawn
this->vPieceSet->push_back(pPiece);
}
// Pawn is now out of scope and pPiece points to the memory location Pawn *used* to be at (but will likely be overwritten soon).
// As soon as this function returns, you have the same problem with pos
}
You need to allocate those variables on the heap (hence the reason we suggested smart pointer wrappers).
Let's say you have this:
class foo {
public:
virtual int myFunc() = 0;
///...
virtual bool who() = 0; // don't want to implement this
};
class bar : public foo {
public:
int myFunc() {return 3;}
//...
bool who() {return true;} // don't want to implement this
};
class clam : public foo {
public:
int myFunc() {return 4;}
//...
bool who() {return false;} // don't want to implement this
};
int main() {
std::vector<foo*> vec (2, NULL);
vec[0] = new bar();
vec[1] = new clam();
// copy vec and allocate new ptrs as copies of the data pointed to by vec[i]
std::vector<foo*> vec2 (vec.size(), NULL);
for ( int i=0; i<vec.size(); ++i ) {
// obviously not valid expression, but it would be nice if it were this easy
//vec2[i] = new foo(*vec[i]);
// the hard way of copying... is there easier way?
if (vec[i]->who()) {
vec2[i] = new bar ( * static_cast<bar* >(vec[i]) ) ;
} else {
vec2[i] = new clam( * static_cast<clam*>(vec[i]) );
}
}
return 0;
}
What I want is some simple way of having the compiler look up in its bookkeeping and allocating/copying vec2[i] according to the stored type of *vec[i]. The workaround is to just make a virtual function which basically returns a value specifying what type *vec[i] is, then doing a conditional allocation based on that.
A common approach goes like this:
class foo {
public:
virtual foo* clone() = 0;
};
class bar : public foo {
public:
virtual bar* clone() { return new bar(*this); }
};
class clam : public foo {
public:
virtual clam* clone() { return new clam(*this); }
};
One way you can do it is by using a dynamic cast to determine type of an object such as done here (Finding the type of an object in C++). but the easiest way would probably be to use typeid.
(assuming you want to maintain your way of using type as a determiner, otherwise I would recommend Joachim's or Igor's as better alternatives :) )
you can use the dynamic_cast to downcast and test the type,
bar* pbar = dynamic_cast<bar*>(vec[i])
if (pbar) {
vec2[i] = new bar ( * static_cast<bar* >(vec[i]) ) ;
} else {
vec2[i] = new clam( * static_cast<clam*>(vec[i]) );
}
see for more info in dynamic_cast
http://www.cplusplus.com/doc/tutorial/typecasting/
I have a struct ( can be class ) and is defined in another class as shown
struct A{
somedata_A;
somespecificimplementation_A(someclass *S1);
};
class someclass{
somedata_someclass;
A a;
};
main(){
someclass c1, *c2;
c2 = &c1;
c1.a.somespecificimplementation_A(c2);
}
How do I verify that c2 is indeed a reference for c1? Pardon me for putting up this example as it is obvious that c2 is reference for c1.
Update: A does not store a pointer to someclass
If you don't know nothing about parent, compare member' adresses
void A::somespecificimplementation_A(someclass *S1)
{
if (this == &(S1->a)) {
// parent == S1
} else {
// parent != S1
}
}
Like that:
struct A{
int somedata_A;
int somespecificimplementation_A(someclass *S1){
if ((void*) &(S1->a) == this)
{
std::cout << "S1 is a pointer to myself" << std::endl;
return 1;
}
return 0;
}
};
Assuming struct A has a pointer to c1, you can then take a pointer to c2 and compare pointer values? Similar to what you would do with assignment operator overloads?
Why go the way around and pass a pointer of your class to the nested struct which you then have to test, when you can instead give a reference to the parent by the parent during its construction?
class someclass
{
public:
struct a
{
void foo()
{
parent.doSomething();
}
private:
friend someclass;
a(someclass & parent)
: parent(parent)
{}
someclass & parent;
} a;
someclass() : a(*this) {}
private:
void doSomething()
{
}
};
Although technically unspecified, the following will work on
most modern, general purpose machines:
void A::somespecificimplementation_A( someclass* S1 )
{
char const* s = reinterpret_cast<char const*>( S1 );
char const* t = reinterpret_cast<char const*>( this );
if ( this >= s && this < s + sizeof( someclass ) ) {
// This A is a member of S1
} else {
// This A isn't
}
}
Having said that, I would stress:
This is not specified by the standard. It will work on
machines with a flat, linear addressing, but may fail (give
false positives) on a machine with e.g. segmented memory.
I'd seriously question the design if A needs to know who it
is a member of.
And if A really does need this information, it really should store
a pointer to someclass, which is passed in to its constructor, so that the dependency is manifest.