so i am trying to build a game and i have the following code:
// Vector2 is just a struct that represents a vector is 2D space.
// predefining these structs
struct SILO;
struct ICBM;
struct MISSILE;
struct ICBM{
Vector2 launch;
Vector2 target;
Vector2 pos;
int Velocity;
ICBM(){
// Implementation not shown
}
void move(){
// implementation not shown
}
};
struct MISSILE{
Vector2 launch;
Vector2 target;
Vector2 pos;
int Velocity;
MISSILE(Vector2 t, SILO origin){
launch = (Vector2) {origin.Object.x, origin.Object.y};
target = t;
pos = launch;
Velocity = 10;
}
void move(){
// implementation not shown
}
};
struct SILO{
Rectangle Object; // Rectangle has attributes x and y
Vector2 pos;
};
I predefined all of the structs in the beginning so they can reference eachother. However, the constructor of the struct MISSILE will result in an error saying that SILO is an incomplete type.
I could change the constructor parameter into MISSILE(Vector2 t, SILO* origin). However, when i try to access the attributes, it will result in the same error.
Is there any way I can solve this problem WITHOUT changing the position of where SILO is defined?
You could use a SILO* in your MISSILE constructor, instead a copy of the whole object?!
MISSILE(Vector2 t, SILO* origin){
launch = (Vector2) {origin->Object.x, origin->Object.y};
Related
I have a class ShapeDisplay that stores a set of Rectangles. I would like to store them sorted, therefore I use a std::set. My intention is to provide a custom comparator, which compares the origin (x, y) of the rectangle to a reference point (x, y) in the display.
However, in order to achieve this, the comparator needs access to m_reference. How do I use a custom comparator, that needs access to the class members? Is my design flawed? I know there are newer ways to provide the comparator as in this link, but that doesn't solve my access issue.
Alternatively, I could just have a std::vector that I keep sorted, such that each new Rectangle is inserted in the right position. But since std::set::insert() should do that automatically with a custom comparator, I would prefer that.
Thank you.
struct Point
{
int x;
int y;
};
struct Rectangle
{
int x;
int y;
int width;
int height;
};
class ShapeDisplay
{
void insertShape(Rectangle rect)
{
m_shapes.insert(rect);
}
void setReference(Point reference)
{
m_reference = reference;
}
private:
struct CenterComparator
{
bool operator() (const Rectangle & a, const Rectangle & b) const
{
double distA = std::sqrt(std::pow(a.x - m_reference.x, 2)
+ std::pow(a.y - m_reference.y, 2));
double distB = std::sqrt(std::pow(b.x - m_reference.x, 2)
+ std::pow(b.y - m_reference.y, 2));
return distA < distB;
}
};
std::set<Rectangle, CenterComparator> m_shapes;
Point m_reference;
};
CenterComparator isn't related to ShapeDisplay, it isn't aware of its members and it isn't derived from ShapeDisplay. You need to provide CenterComparator with its own reference Point. You then need to provide an instance of CenterComparator whose reference point is set.
Note that if you change that comparator's reference point in any way you will break std::set's sorting resulting in Undefined Behavior if you try to use it. So whenever setReference is called, you need to create a new set with a new comparator and copy over the old set.
Here is your code, adapted with these changes. I assumed you meant setReference and insertShape to be part of the public interface.
#include <cmath>
#include <set>
struct Point
{
int x;
int y;
};
struct Rectangle
{
int x;
int y;
int width;
int height;
};
class ShapeDisplay
{
public:
void insertShape(Rectangle rect)
{
m_shapes.insert(rect);
}
void setReference(Point reference)
{
m_reference = reference;
// Create a comparator using this new reference
auto comparator = CenterComparator{};
comparator.reference = m_reference;
// Create a new set
auto new_shapes = std::set<Rectangle, CenterComparator>(
std::begin(m_shapes), std::end(m_shapes), // Copy these shapes
comparator); // Use this comparator
m_shapes = std::move(new_shapes);
}
private:
struct CenterComparator
{
bool operator() (const Rectangle & a, const Rectangle & b) const
{
double distA = std::sqrt(std::pow(a.x - reference.x, 2)
+ std::pow(a.y - reference.y, 2));
double distB = std::sqrt(std::pow(b.x - reference.x, 2)
+ std::pow(b.y - reference.y, 2));
return distA < distB;
}
Point reference;
};
std::set<Rectangle, CenterComparator> m_shapes;
Point m_reference;
};
I have two classes a 3D vector class(Vector3) with an array of 3 floats as its member(float[3]), and a 3 by 3 matrix class that stores 3 of these vectors in another array(Vector3[3]). My vector class requires the matrix class to rotate about an axis, and my matrix class requires vectors for everything. I was using forward declarations and pointers to deal with it, like in this question: What is the best way to deal with co-dependent classes in C++?, but there must be a better way to design this to avoid that altogether. At the moment I declare a pointer to Vector3 on my matrix header file, and then initialize it with new in my implementation file, yet this feels clumsy. Any pointers(no pun) on how to solve this issue?
Edit: I use the vector class to represent a 3D point which I intend to rotate about an arbitrary axis.
The code as I would like it to work:
//Vector3.h
#include "Matrix3.h"
class Matrix3;
class Vector3 {
float xyz[3];
};
//Vector3.cpp
Vector3 Vector3::rotatePoint(Vector3 o, Vector3 a, float theta) {
Vector3 point = (*this);
Vector3 x = Vector3(1,0,0);
Vector3 y = Vector3(0,1,0);
Vector3 z = Vector3(0,0,1);
// Create new coordinate system
Vector3 new_coord[4];
new_coord[0] = o;
new_coord[1] = a.normalize();
unsigned closer_to;
if (a*x < a*y) {
new_coord[2] = (a % x).normalize();
closer_to = 0; // x
}
else {
new_coord[2] = (a % y).normalize();
closer_to = 1; // y
}
new_coord[3] = (a % new_coord[2]).normalize();
// Transform point to new coord system
Matrix3 trans_matrix = Matrix3(new_coord[0], new_coord[1], new_coord[2]);
point = trans_matrix*(point - o);
// Rotate about a by theta degrees
Matrix3 r_m(closer_to, theta);
point = r_m*point;
//Transform back to original coord system
point = (trans_matrix.inverse()*point) + o;
return point;
}
//Matrix3.h
#include "Vector3.h"
class Vector3;
class Matrix3 {
Vector3 rows[3];
}
The code that I use to make it work:
//Vector3.h
class Matrix3;
class Vector3 {
float xyz[3];
};
//Matrix3.h
#include "Vector3.h"
class Vector3;
class Matrix3 {
Vector3 *rows;
}
//Matrix3.cpp
Matrix3::Matrix3() {
rows = new V3[3];
}
I took the advice given by #n.m. and #Chris Dodd's and just removed the Matrix3 include from my Vector header, and into my Vector implementation file, like this:
//Vector3.h
class Vector3 {
float xyz[3];
}
//Vector.cpp
#include "Vector3.h"
#include "Matrix3.h"
//Matrix3.h
#include "Vector3.h"
class Vector3;
class Matrix3 {
Vector3 rows[3];
}
//Matrix3.cpp
#include "Matrix3.h"
Since you're dealing with vectors and matrices, you could define a single matrix class with templates for the dimensions (and maybe the element type) -- the vector class would then (depending on the type of vector) be a matrix with one of the dimension = 1. If you do this, you only end up with one class, one set of code and all the functionality required to do everything you want. You avoid any inter-class dependencies since you only have one class!
The class itself would look something like this:
template<unsigned m, unsigned n, typename T = float>
class matrix {
T e[m * n];
public:
T* operator [](unsigned i) { return e + i; }
T * const operator [](unsigned i) const { return e + i; }
/* repeat for -, *, / -- same pattern */
matrix<m,n>& operator += (matrix<m,n> const& a) {
for (unsigned i = 0; i < m * n; ++i) e[i] += a.e[i];
return *this;
}
};
You should then define any functions which does not take equal sized matrices outside the class (this is why we have the [] operator). Note that the * and / operators work on all elements and do not calculate the usual matrix-matrix multiplication or matrix-matrix division. Instead, you will want to have a invert function and a multiply function.
template<unsigned m, unsigned n, unsigned k>
matrix<m,k> const multiply(matrix<m,n> const& a, matrix<n,k> const& b);
template<unsigned m>
matrix<m,m> const invert(matrix<m,m> const&);
template<unsigned m, unsigned n>
matrix<n,m> const transpose(matrix<m,n> const&);
Note that, if you have a method for inverting a generic non-square matrix, of which I know none, the above template will only work for a square matrix. Filling in the code for the functions I leave to you as an exercise.
To get a 3 vector and a 3x3 matrix, you could typedef them as so:
typedef matrix<3,1,float> vector3f;
typedef matrix<3,3,float> matrix3x3f;
Remember to add comparison operators as well as anything else you need.
If you wish, you could add matrix-scalar and scalar-matrix operators and functions as well (to ease, say, adding a scalar to all the elements in a matrix).
If you want better control over the elements in the [] operators, you could use vectors as the base class and then define matrices as a vector of vectors. This will give you the same advantages but may suit your mindset more easily (a lot of people think of vectors and matrices as being distinct types).
in .h:
enum collisionType {AB, BA, AoverB, AunderB};
struct Collision {
public:
collisionType type;
glm::vec2 point1;
glm::vec2 point2;
Collision(enum collisionType, glm::vec2, glm::vec2);
};
in .cpp:
Collision::Collision(enum collisionType collisType, glm::vec2 p1, glm::vec2 p2) : type(collisType), point1(p1), point2(p2)
{
}
using it
std::vector<Collision> collisions;
glm::vec2 point1(11.0, 12.0);
glm::vec2 point2(12.0, 13.0);
collisions.push_back(Collision(AoverB, point1, point2));
Getting error C2512: 'Collision' : no appropriate default constructor available, why?
You can read here the requirements for a type T to be well suited for std::vector.
Default-constructible is not listed there.
I also tried compiling this minimal code sample, in which X doesn't have a default constructor, and it compiles fine with MSVC:
#include <vector>
struct X {
X(int a, int b) : A(a), B(b) {}
int A;
int B;
};
int main() {
std::vector<X> v;
v.push_back(X(10,20));
}
So, the problem must be elsewhere in your code.
Anyway, you may want to add a constructor with no arguments to make your Collission class "default-constructible", and make the compiler happy:
struct Collision {
// Default constructor.
// Initialize data members to some init values.
Collision() {
...
}
PS Note that struct in C++ is equivalent to class { public: ..., so you can omit the public: line in your code: it's implied by the use of the keyword struct.
The following code compiles fine, it's something else that is the problem.
#include <glm/vec2.hpp>
#include <vector>
enum collisionType {AB, BA, AoverB, AunderB};
struct Collision {
public:
collisionType type;
glm::vec2 point1;
glm::vec2 point2;
Collision(enum collisionType, glm::vec2, glm::vec2);
};
Collision::Collision(enum collisionType collisType, glm::vec2 p1, glm::vec2 p2) : type(collisType), point1(p1), point2(p2)
{
}
int main()
{
std::vector<Collision> collisions;
glm::vec2 point1(11.0, 12.0);
glm::vec2 point2(12.0, 13.0);
collisions.push_back(Collision(AoverB, point1, point2));
}
I'm trying to create classes for mathematical vectors in various dimensions, and since they have much in common I created a templated base class with the vectors size as the template parameter. I'm subclassing because I want different constructors (e.g. Vec2f(float x, float y), Vec3f(float x, float y, float z)) and additional functions like the cross product for 3 dimensional vectors.
My Problem: What should operator+ in the baseclass return? If it returns an instance of the baseclass then Vec3f + Vec3f returns Vecnf, but it should return Vec3f. Can this be achieved somehow?
Here is a code example:
template <size_t n>
class Vecnf {
public:
Vecnf operator+(Vecnf const & vec) const {
return Vecnf(*this) += vec;
}
Vecnf & operator+=(Vecnf const & vec) {
for (int i = 0; i < n; ++i) {
elements[i] += vec.elements[i];
}
return *this;
}
protected:
std::array<float, n> elements;
};
class Vec3f : public Vecnf<3> {
public:
Vec3f(float x = 0.0f, float y = 0.0f, float z = 0.0f);
Vec3f crossProd(Vec3f const & vec);
};
With this implementation, the following:
Vec3f a, b;
Vec3f c = a + b;
gives the compile time error
error: conversion from 'Vecnf<3u>' to non-scalar type 'Vec3f' requested
I'm using TDM GCC version 4.8.1 on Windows 8 Pro. I'm using c++11, so your solution can use it as well, but since I don't think it's crucial I haven't flagged the question with it. Thank you in advance :)
You could make the constructor a variadic template, thereby solving your first problem and eliminating the need to even use inheritance:
template <size_t n>
class Vecnf
{
std::array<float, n> elements;
public:
template <typename ... Args>
Vecnf(Args ... args):
elements {{static_cast<float>(args)...}}
{}
// other methods, operators etc...
};
Now you can make typedef's for the commonly used sizes if you like:
typedef Vecnf<3> Vec3f;
In my opinion, you could even improve this by adding another template parameter for the type you want to store in the array. It could default to float of course.
Also, it shouldn't be too hard to implement the cross-product in a generic way...
You can just define an operator+ on vec3f that does what you want it to. It can have a differing return type to vecnf's as long as it's a subtype of it and it will still override it.
Better solution is what #JorenHeit introduced; that actually is what you wanted, together with two typedefs. This solution is c++03 compatible though, and his isn't.
I have this class:
class Texture
{
public:
//I need this variable in this format
float diffuseColor[3];
}
But I'd like to make an easier interface than dealing with "diffuseColor[0]" and such, something like:
myTexture.color.r = 1.0f; //this is diffuseColor[0]
So I'm trying to get a class that works as a shell to the diffuseColor values, something like:
class Color
{
public:
float *r, *g, *b;
}
And in my Texture class:
class Texture
{
public:
Texture()
{
color.r = &diffuseColor[0];
color.g = &diffuseColor[1];
color.b = &diffuseColor[2];
}
Color color;
private:
float diffuseColor[3];
}
But the way it is now, I have to de-reference the color values if I want to use them:
(*myTexture.color.r) = 1.0f;
How can I achieve this without having to de-reference it everytime I want to use it?
You can use references which would be initialized in the member initializer list:
struct Color {
Color(float* colors): r(colors[0]), g(colors[1]), b(colors[2]) {}
float& r;
float& g;
float& b;
};
class Texture {
float diffuseColor[3];
public:
Color color;
Texture(): diffuseColor(), color(this->diffuseColor) {}
};
If you need to copy and/or assign Texture objects, you'll also need to implement a copy constructor and an assignment operator. Also note that this convenience has a relatively steep costs: both the pointers and the reference approach will increase the size of the Texture objects by 3 pointer. You might be better off to use accessors, instead, e.g.:
class Texture {
float diffuseColor[3];
public:
float& r() { return this->diffuseColor[0]; }
float& g() { return this->diffuseColor[1]; }
float& b() { return this->diffuseColor[2]; }
};
Maybe you can use the union language feature of C++:
union ColorUnion {
// first representation (Texture)
struct TextureColor {
float diffuseColor[3];
}
// second representation (RGB)
struct RGBColor {
float r;
float g;
float b;
}
};