I have nested structs, where the base has a pure virtual function.
(The following examples are a bit pseudo-ish, but describe the purpose)
struct Base {
int id=0;
virtual std::wstring toString() = 0;
}
struct Top1 : public Base {
id=1;
int val = 5;
std::wstring toString() { return L"need to use string stream. id="+id+" val="+val; }
}
struct Top2 : public Base {
id=2;
std::string val = "Hello!";
std::wstring toString() { return L"need to use string stream. id="+id+" val="+val; }
}
I wish to have a single table for all the different types, so I created this:
struct BaseFootprint{
union{
Top1 top1;
Top2 top2;
}
std::vector<BaseFootprint> data;
Calling the function in the following way does not work:
for(int i=0;i<data.size;i++){
std::cwout <<data[i].toString()<< std::endl;;
}
I have tried:
std::cwout << ((base)data[i]).toString() << std::endl;
And:
std::cwout << (Top1)data[i].toString() << std::endl;
But it always says data[i]-> empty.
So, to my disappointment, and not unexpected, the pure virtual function does not point to the correct top function depending on how the struct data is viewed via the union.
As my end product will hold 100s of different top types, I am hoping for a dynamic solution as opposed to making a hard-written selection. A dynamic solution will allow me to add new types without altering the base code, and this is what I hope for.
It would be awesome if there is a way to achieve this as described.
Union is not the right tool.
Ignoring the other compiler errors, you need to access particular member of union (e.g. data[i].top1) and you cannot access any member except the one that was last written to (which means you would need to somehow remember which one is which in the vector). std::variant is a typesafe union, but you would still need a lot of boilerplate code to access correct member.
The normal way to use polymorphism in C++ is through pointers:
int main()
{
std::vector<std::unique_ptr<Base>> data;
data.push_back(std::make_unique<Top1>());
data.push_back(std::make_unique<Top2>());
for (auto& ptr : data)
{
std::wcout << ptr->toString();
}
}
The problem I was having is that I was not calling the constructor for the union objects.
For example...
If the union object needs to be Top1 then its constructor should be called...
new (&data[i]->top1) Top1();
At the other end the polymorophic methods worked for me with the following changes...
Remove the pure from the base method, like so...
virtual std::wstring toString() { return L"Base"; };
Add Base to the union, like so...
union{
Base base;
Top1 top1;
Top2 top2;
}
The continuous chunk of memory of objects can now be processed, by calling the polymorphic method...
for (std::vector<BaseFootprint>::iterator bfi = data.begin(); bfi != data.end(); bfi++) {
std::wcout << (*bfi).base->toString() << std::endl;
};
If you have never pushed a continuous chunk of memory of objects to the L1 cache before, you're welcome!
Related
I have a struct:
struct MyStruct{
}
I want to be able to add a pointer to a variable at runtime
std::string myString = "Hello";
MyStruct my_struct;
As an example if there was a function that did this it would be like this
std::add_to_struct(&my_struct, &myString);
and you can retrieve that variable using:
std::get_struct_variable<std::string>("myString");
Adding fields to structs or classes at runtime isn't allowed, by design. More dynamic languages like JavaScript support this because the runtime "knows" which fields each object has, and what their names are. In C++ (ignoring debug info), this info is only known at compile time. At runtime, an instance of MyStruct is just a piece of memory of length sizeof(MyStruct). There is no room to add additional fields. Even if MyStruct instances could be made longer, any code complied to handle a MyStruct wouldn't know how to interpret the additional bytes, because that info wasn't available at compile time.
If you want a dictionary-like object that can associate arbitrary string names with values, use std::map like so:
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string,int> dict;
dict["hello"] = 100;
dict["good bye"] = 200;
std::cout << dict["hello"] << std::endl;
return 0;
}
In this example, the values are ints. If you need values of different types in the same data structure, there are a few options. You could change the values from int to void*:
int main() {
std::map<std::string,void*> dict;
dict["hello"] = new int(100);
std::cout << *static_cast<int*>(dict["hello"]) << std::endl;
return 0;
}
Instead of storing the values directly in the map, we instead create values of any type on the heap, and only store their pointers in the map. This simple, but error-prone, and I don't recommend it. void* circumvents C++'s type safety by making all types interchangeable. Notice that when we retrieve our data from dict, the retrieving code has to know to cast the pointer back to int. If you cast back to the wrong type, you'll get garbage data.
Also notice that this program leaks memory! You could be diligent about individually freeing each item from each map when you're done with it, or you could used std::unique_ptr to do that automatically. But in either case you're going to find that the code which frees the elements needs to know what type each element is, and how to properly free that particular type. What if one of your types contains pointers to yet more objects that must be freed first?
You could alternatively make the values unions:
typedef union {
int i;
char c;
} IntChar;
int main() {
std::map<std::string,IntChar> dict;
IntChar ic;
ic.i = 100;
dict["hello"] = ic;
std::cout << dict["hello"].i << std::endl;
return 0;
}
This restores some partial type-safety, since you can only interpret the data as one of the types pre-defined in the union. But it has the drawbacks that you must pre-define all possible types in the union, there are limits on what types you can put in a union, and each instance of the union will be sized to accommodate the largest type inside it, which may waste memory if most of your instances use the smaller types.
Union's limitations may be acceptable to you. If not, then the most type-safe and extensible solution, at the expense of more code, is to make map values pointers to a base class type, and then create derived classes for each type you want to put in the dictionary:
#include <iostream>
#include <map>
#include <memory>
#include <string>
class Base {
public:
virtual ~Base() = default;
virtual std::string to_string() = 0;
};
class DerivedInt : public Base {
public:
int i;
DerivedInt(int i_) : i(i_) {}
std::string to_string() override { return std::to_string(i); }
};
class DerivedChar : public Base {
public:
char c;
DerivedChar(int c_) : c(c_) {}
std::string to_string() override { return std::string(&c, 1); }
};
int main() {
std::map<std::string,std::unique_ptr<Base>> dict;
dict["hello"] = std::make_unique<DerivedInt>(100);
dict["good bye"] = std::make_unique<DerivedChar>('z');
std::cout << dict["hello"]->to_string() << std::endl;
std::cout << dict["good bye"]->to_string() << std::endl;
return 0;
}
This way, each derived class is responsible for its own particular fields, and the calling code need not worry about their differences. If any derived type needs to be freed in a particular way, it can implement its own destructor to do so.
This is all assuming, of course, that your use-case actually needs to associate arbitrary names with arbitrary data. If you're just trying to port a scripting language coding style over to C++ by using dictionaries instead of classes and structs, I'd recommend instead that you embrace the strengths and limitations of C++ while working in C++. That means deciding ahead of time what classes and fields you need, and declaring them up front so the compiler can help spot your mistakes.
I'm trying to create a generic class that wraps a struct from structures in a C library. Consider these two structure definitions.
struct s32 {
int a:
int b;
};
struct s64 {
long a;
long b;
};
I'm trying to determine if there is a generic construct in C++ which would let transparently create a wrapper around these structs such as I don't have to explicitly write the code to access the long or int variations.
Since I don't know what construct would provide this other than making an interface and implementing both versions - this is just pseudo code.
template <typename T, typename I> class SWrapper {
T s;
public:
SWrapper(T _s) : s(_s) {};
I get_a() { return this->s->a; }
}
class S32 : SWrapper<s32*, int> {};
class S64 : SWrapper<s64*, long> {};
int main(void) {
s32 s1 = { 1, 2 };
s64 s2 = { 3, 4 };
SWapper* S = new S32(&s1); // I know this is incorrect
S = new S64(&s2); //
assert(s.get_a() == 3);
}
I know why this doesn't work. Templates are determined at compile time and so the compiler can't determine what S actually is when using the generic SWapper without actual type-parameters and using type-parameters would create an erasure that excludes the other type so they cannot both be assigned to the same address.
Besides C macros or implementing all the code for two classes implementing the same interface is there some construct in C++ to produce the same effect?
[Update]
After considering several patterns I've settled on a pattern which I consider to be "the least cost to write". It is very close to the answer by #JaMiT.
The benefits I see are:
No need to completely implement the code that accesses the C struct's twice.
No need to constantly redefined generic types <> when wrapper class is used.
Again please just consider this pseudo code.
class SWrapper {
private:
const std::unique_ptr<s32> s32impl_;
const std::unique_ptr<s64> s64impl_;
public:
SWrapper(s32* s) : s32impl_(s), s64impl_(nullptr) {};
SWrapper(s64* s) : s32impl_(nullptr), s64impl_(s) {};
long get_a() {
// could be improved with macros
return (s32impl_->get() == nullptr) ? s32impl_->a : s64impl_->a;
}
}
The problem with your S is not so much that templates are determined at compile time, but rather than pointers cannot point to unrelated types. To give you the same setup without templates:
class A;
class B;
class C * S = ??? // Cannot point to another class.
You might see a connection between the classes you are trying to use, but to the compiler SWrapper<s32*, int> and SWrapper<s64*, long> are as different as A and B.
In order to have a pointer pointing to different types, the types need to share a common ancestor. This is not hard to do when you have enough restrictions on the structures you are getting from the C library. The question implies that these structures have a common logical structure, but differ in the types of members. The comments clarified that the types of the members could all be implicitly cast to a common type. (Specifically, they are all signed integers of some variety.) So one could define the interface you want to see:
class WrapBase {
public:
virtual ~WrapBase() {}
virtual long get_a() = 0;
virtual long get_b() = 0;
};
Note that the member functions return long. This is the type that things will be implicitly cast to. If needed, it could be long long.
Next, use your template to adapt this base to the various structures:
template <typename T>
class Wrap : public WrapBase {
private:
T & data;
public:
explicit Wrap(T & from_c) : data(from_c) {}
long get_a() { return data.a; }
long get_b() { return data.b; }
};
Now you can write functions that take wrapped structures as arguments. Well, presumably that is the sort of thing you want to do. Manually calling new is undesirable, but it does provide a quick-and-dirty demo showing the polymorphism in action.
// Demonstration using the question's main() as context:
WrapBase * S = new Wrap<s32>(s1);
std::cout << "s1: {" << S->get_a() << ',' << S->get_b() << "};\n";
delete S;
S = new Wrap<s64>(s2);
std::cout << "s2: {" << S->get_a() << ',' << S->get_b() << "};\n";
delete S;
Since the polymorphism works for pointers, it will work for references used as function parameters.
One downside of the above is that you have to declare all the access functions twice. And there is additional work to get the values from the wrapped structures. An easier interface to code (and use?) would involved converting, rather than wrapping, the data. This involves a greater upfront cost when obtaining the data, but cheaper access costs. Whether or not this is an option depends on execution constraints, but it's probably worth trying to see how well it works.
struct Converted {
long a;
long b;
template <typename T>
explicit Converted(T & source) :
a(source.a),
b(source.b)
{}
};
Again using long as the type to which everything can be implicitly converted. Now you can use the data with a more familiar access syntax. (If you still want getter functions -- a reasonable design choice -- the compiler should be able to inline them, something it could not do with the virtual functions.)
// Demonstration using the question's main() as context:
Converted S{s1};
std::cout << "s1: {" << S.a << ',' << S.b << "};\n";
Converted SS{s2};
std::cout << "s2: {" << SS.a << ',' << SS.b << "};\n";
I've began making a program in linux with c++ and I'm trying to make it work on windows. It compiles fine, but when run I get this error: "1 [main] Trails of Cold Steel Simulator 8748 cygwin_exception::open_stackdumpfile: Dumping stack trace to Trails of Cold Steel Simulator.exe.stackdump". In the stack trace this exception occurs: "Exception: STATUS_ACCESS_VIOLATION". Here's some code;
#include "Tachi.h"
#include "AutumnLeafCutter.h"
#include <iostream>
#include "Weapon.h"
#include "Armour.h"
#include "Shoes.h"
int main() {
int stats[12] = {15,110,10,4,2,1,2,4,4,3,7,1};
Tachi* Tachi1 = new Tachi(stats, "Tachi");
Tachi1->addEquipment(new PracticeSword());
Tachi1->addEquipment(new LeatherJacket());
Tachi1->addEquipment(new WorkBoots());
Tachi1->addMasterQuartz(new Forcelvl1());
std::string input;
std::cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
while(input != "q") {
std::cout << "Your current stats are:" << std::endl;
std::cout << "\n";
std::cout << "HP EP STR DEF ATS ADF SPD DEX AGL MOV RNG" << std::endl;
for(int i = 0; i < 12; i += 1) {
std::cout << Tachi1->getBaseStats()[i] << " ";
}
std::cout << "\n\n";
std::cout << "Select a Craft by typing its name:" << std::endl;
std::cout << std::endl;
for(int i = 0; i < Tachi1->getCrafts().size(); i++) {
std::cout << Tachi1->getCrafts()[i]->getName() << std::endl;
}
std::cout << std::endl;
getline(std::cin, input);
if(Tachi1->findCraft(input) != NULL) {
Tachi1->useCraft(input);
} else {
std::cout << "You do not have this craft." << std::endl;
}
std::cout << "\n\n\n";
}
}
Im extremely sorry for any formatting, I've never posted here. The error comes from lines 14,15,16 and 18. When I replaced all the "new xxx()" with NULL and comment out the body of the function with them, the program works. It does this for both addEquipment() and addMasterQuartz(). This is the functions;
void Character::addEquipment(Equipment* e) {
equipment.push_back(e);
std::cin.get();
for(int i = 0; i < 12; i++) {
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
}
}
and
void Character::addMasterQuartz(MasterQuartz* mq) {
masterQuartz = mq;
for(int i = 0; i < 12; i++) {
baseStats[i] += masterQuartz->getStatsModifier()[i];
}
}
Im guessing its a problem with the baseStats[i] += xxx stuff as its the only thing that occurs in both, but I have no idea how to fix that. It could also occur when the stuff is made using new xxx().
I can provide whatever else is needed. Thanks!!!!
EDIT:
I kept testing and the problem seems to lie in the creating of the objects. It worked on linux. Here is one of the object codes, they are all similiar and all crash the program;
#include "Armour.h"
Armour::Armour(int* sm, std::string n):Equipment(sm, n) {}
LeatherJacket::LeatherJacket():Armour(stats, armourName) {}
with header file;
#ifndef ARMOUR_H
#define ARMOUR_H
#include "Equipment.h"
class Armour:public Equipment {
public:
Armour(int* sm, std::string n);
};
class LeatherJacket:public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
#endif
As soon as I remembered I did this I tried compiling (I think) with -std=c++11, it didnt help.
This is your error
baseStats[i] += equipment[equipment.size()]->getStatsModifier()[i];
By definition this is an out of bounds access on your vector, if a vector has a certain size, then the valid indexes are 0 to size - 1, not 0 to size.
It's fairly obvious that you wanted to access the last item in the vector. You can do that like this
baseStats[i] += equipment[equipment.size() - 1]->getStatsModifier()[i];
but even clearer is to use the back method.
baseStats[i] += equipment.back()->getStatsModifier()[i];
Another way would be to use the e variable you've just pushed onto the vector.
baseStats[i] += e->getStatsModifier()[i];
Adding some detail to the problem spotted by Useless, this code is incorrect.
class LeatherJacket : public Armour {
int stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
std::string armourName = "Leather Jacket";
public:
LeatherJacket();
};
LeatherJacket::LeatherJacket() : Armour(stats, armourName) {}
The problem is the order in which things happen. First the Armour constructor is called, then the stats and armourName variables are initialised. So the call to the Armour constructor is using uninitiialised variables and will likely crash.
Several solutions possible, the best is probably to use virtual functions.
Making a couple of assumptions about Equipment (which isn't specified the question) it seems you should do something like this.
// header file
class Equipment
{
public:
virtual ~Equipment() {}
virtual std::string getName() const = 0;
virtual const int* getStatsModifier() const = 0;
};
class Armour : public Equipment
{
};
class LeatherJacket : public Armour
{
static const int stats[12];
public:
virtual std::string getName() const { return "Leather Jacket"; }
virtual const int* getStatsModifier() const { return stats; }
};
// source file
const int LeatherJacket::stats[12] = {0,0,0,5,0,0,0,0,0,0,0,0};
This answer adds pure virtual functions to the base class Equipment (which has become an interface), and implements those functions in LeatherJacket. Because the functions are virtual the appropriate function will always be called and there no need to pass the information down to Equipment. Also since it seems to be per-class constant data, stats has been made static const. Until you get to C++17 static const arrays must be defined in a source file, not the header file, as shown above.
Firstly, I'm going to replace the int[12] arrays with a proper type. Partly so the magic number 12 isn't littered all over the code and hard to change later, and partly because it will behave better (ie, not decay to a pointer in some contexts). This needs C++11.
#include <array>
using Stats = std::array<int, 12>;
To me it looks like Armour should have stats and a name, initialized from the arguments passed to its constructor (which you currently ignore).
Like so:
class Armour: public Equipment {
public:
Stats m_stats;
std::string m_name;
Armour(Stats const& s, std::string const &n) : m_stats(s), m_name(n) {}
};
You were already passing those two arguments to the constructor - you just weren't doing anything with them. Now you are.
This means that when we later have leather, scale, chain and plate subclasses, I can have a pointer of type Armour* and not need to worry about which subclass I'm looking at: the stats are available right there in the base class.
I made the members public, which is generally bad style, to save space. It might not matter for your use. I named the members with the m_ prefix so they can't accidentally get confused with similarly-named non-members. It's broadly good style but not essential.
LeatherArmour doesn't need an additional copy per instance, it just needs one of each for the whole class - so they should be const static members.
class LeatherJacket: public Armour {
static const Stats stats {0,0,0,5,0,0,0,0,0,0,0,0};
static const std::string name{"Leather Jacket"};
public:
LeatherJacket() : Armour(stats, name) {}
};
I made the LeatherJacket-specific stat values static const by writing static const in front of them.
The static means that every LeatherJacket has the same base stats, so you don't need a copy per instance, just one copy for the whole class. It's const because the base stats for leather jackets never change over time. You still have the base class member Armour::m_stats which can change as your individual leather jacket gets damaged, repaired, buffed or whatever.
Again, the LeatherJacket constructor was already passing (the equivalent of) these members to the base class constructor, but now they already exist (see the link above about static storage duration). The original instance variables didn't exist when you used them, because the derived (LeatherJacket) object and its data members aren't really constructed until after the base class subobject.
I'm pretty new to C++ and am having trouble making a pointer point from one class to another. This is what I have, it compiles without error, but doesn't work the way I want it to.
JungleMap *Map;
class JungleMap
{
public:
void goNorth()
{
cout << "You are going north towards the river.\n";
delete[] Map;
RiverMap *Map;
}
}
class RiverMap
{
public:
void goNorth()
{
cout << "You are going north away from the river.\n";
delete[] Map;
JungleMap *Map;
}
}
int main()
{
Map->goNorth();
Map->goNorth();
}
This is what the output is:
You are going north towards the river.
You are going north towards the river.
And this is what I would like the output to be:
You are going north towards the river.
You are going north away from the river.
How do I achieve this? It's really bugging me, especially since it compiles without problems.
Just creating a JungleMap* doesn't create a JungleMap. You formed a pointer, but didn't point it anywhere!
This is particularly dangerous since you then dereference it, and later attempt to delete through it. Yes, this compiles, because a compiler cannot diagnose this in the general case (and is never required to try), but you'll get everything at runtime from silent nothingness, to a crash, to a nuclear explosion.
You are also trying to invoke different functions in two different classes, through changing the type of a pointer (without any inheritance, at that), which is simply not possible and will prevent your code from compiling, even though you've tried to get around it by redeclaring variables locally. I could list a ream of misunderstandings but suffice it to say it's time to read a good introductory C++ book.
I would suggest a combination of inheritance and dynamic allocation, if I knew what you were trying to achieve. A common mistake on SO is to provide nonsense code, then expect us to know what your goal is from that nonsense code; unfortunately we have about as much idea what you really meant to do as the C++ compiler does!
You could make this work (to at least a minimal degree) by creating a base class from which both JungleMap and RiverMap derive. You'd then have a pointer to the base class, which you'd point at an instance of one of the derived classes. You'll also need to rearrange the code somewhat to get it to compile.
class Map {
public:
virtual void goNorth() { cout<<"Sorry, you can't go that way"; }
virtual void goSouth() { cout<<"Sorry, you can't go that way"; }
};
Map *map;
class RiverMap;
class JungleMap : public Map {
public:
void goNorth();
};
class RiverMap : public Map {
public:
void goSouth();
};
void JungleMap::goNorth() {
cout<<"You are going north towards the river.\n";
delete map;
map=new RiverMap;
}
void RiverMap::goSouth() {
cout<<"You are going south towards the jungle.\n";
delete map;
map=new JungleMap;
}
Note: here I'm just trying to say as close to your original design as possible and still have some code that might at least sort of work. I'm certainly not holding it up as an exemplary design, or even close to it (because, frankly, it's not).
What you should do is to sit down and think about the problem you are trying to solve, and make a proper design. In your case you have two "locations", and the "player" should be able to move between these locations. Starting from that we have identified two possible classes (Location and Player) and one behavior (the player can move from location to location).
With the above information, you could do something like this:
class Location
{
public:
void setNorth(Location* loc)
{
north_ = loc;
}
Location* getNorth() const
{
return north_;
}
void setSouth(Location* loc)
{
south_ = loc;
}
Location* getSouth() const
{
return south_;
}
void setDescription(const std::string& descr)
{
description_ = descr;
}
const std::string& getDescription() const
{
return description_;
}
protected:
Location() {} // Made protected to prevent direct creation of Location instances
private:
Location* north_;
Location* south_;
std::string description_;
};
class Jungle : public Location
{
public:
Jungle() : Location()
{
setDescription("You are in a jungle.");
}
};
class River : public Location
{
public:
River() : Location()
{
setDescription("You are close to a river.");
}
};
// The actual "map"
std::vector<Location*> map
void createMap()
{
map.push_back(new Jungle);
map.push_back(new River);
map[0]->setNorth(map[1]);
map[1]->setSouth(map[0]);
}
class Player
{
public:
Player(Location* initialLocation)
: currentLocation_(initialLocation)
{
std::cout << currentLocation_->getDescription() << '\n';
}
...
// Other methods and members needed for a "player"
void goNorth()
{
if (currentLocation_ && currentLocation_->getNorth())
{
currentLocation_ = currentLocation_->getNorth();
std::cout << currentLocation_->getDescription() << '\n';
}
}
void goSouth()
{
if (currentLocation_ && currentLocation_->getSouth())
{
currentLocation_ = currentLocation_->getSouth();
std::cout << currentLocation_->getDescription() << '\n';
}
}
private:
Location* currentLocation_; // The players current location
};
int main()
{
createMap(); // Create the "map"
Player player(map[0]); // Create a player and place "him" in the jungle
// Move the player around a little
player.goNorth();
player.goSouth();
}
In the code above, you have a single player object, which have a "current location". When you move the player around, you simply change the current location for that player. The current location of the player acts as the global Map variable you have.
Note: I'm not saying that this is a good design or code, just that it's simple.
However, if you're truly new to C++, you should probably start with some simpler problems, including tutorials on pointers and inheritance.
You appear to be confusing declaration with assignment.
The following line of code is called a declaration, it tells the compiler the properties and attributes of a thing.
JungleMap *Map;
After this line of code, the compiler knows that "Map" is a symbol (a name) referring to a pointer to a JungleMap.
The compiler doesn't have to do anything with a declaration, unless it would have a side effect, at which point it becomes a definition, which means that the declaration invokes a non-trivial constructor or provides an assignment:
struct Foo {};
struct Baz { Baz() { std::cout << "Baz is here\n"; } };
These are declarations - they don't create instances of objects, they describe the layout and functions for instances. At some point you have to create a concrete instance of them with a definition or a call to new.
struct Foo {};
struct Bar { Bar() { std::cout << "Bar is here\n"; } };
struct Baz {};
int main() {
int i; // no side effects, i is trivial.
char* p; // no side effects, p is a pointer (trivial) type
std::string* sp; // trivial, pointer
Foo f; // trivial
Bar b; // non-trivial, baz has a user-defined ctor that has side-effects.
Bar* bar; // trivial, unassigned pointer type.
Bar* bar2 = new Bar(); // side effects.
Bar bar(); // syntax error, "the most vexing parse"
}
In the above code, we never use "Baz" and we never declare an object of type Baz so the compiler essentially throws it away. Because so many of the variables are trivial and have no side effect, the result of compiling the above will be functionally equivalent to if we had written:
struct Foo {};
struct Bar { Bar() { std::cout << "Bar is here\n"; } };
int main() {
Bar* bar2 = new Bar(); // side effects.
Bar bar(); // syntax error, "the most vexing parse"
}
All of the rest does nothing.
C++ also allows you to re-use names as long as they are in different scopes, but this creates a new, hidden ("shadow") thing:
#include <iostream>
int main() {
int i = 1;
if (i == 1) {
float i = 3.141;
std::cout << "inner i = " << i << '\n';
}
std::cout << "outer i = " << i << '\n';
return 0;
}
The code you wrote will therefore compile, because it is declaring a new and private "Map" inside each of the go functions and then simply never using them.
Note that above I was able to declare i differently inside the inner scope than the outer.
C++ does not allow you to change the type of a variable - in the above code there are two variables called i. When we created the second i, it is a second variable called i the original variable didn't change.
In order to do what you are trying to do, you're going to need to learn about "polymorphism" and "inheritance", C++ concepts that will allow you to describe a "Room" or "Location" and then base JungleMap and RiverMap on that base definition such that you can take a pointer to the core concept, the Room, and write generic code that deals with rooms while moving the specifics of Jungle, River or BridgeMap into specialized functions. But I think that's beyond the scope of a reply here.
I've never seen this in any language, but I was wondering if this is possible using some trick that I don't know.
Let's say that I have a function like
struct A {
// some members and methods ...
some_t t;
// more members ...
};
void test(some_t& x) { // a reference to avoid copying a new some_t
// obtain the A instance if x is the t member of an A
// or throw an error if x is not the t member of an A
...
// do something
}
Would it be possible to obtain the instance of A whose member t is x ?
No unfortunately it's not possible.
If you know that you have a reference to the t member of some A instance, you can get the instance using container_of, e.g. A* pa = container_of(&x, A, t);.
Verifying that the resulting pointer actually is an A is technically possible if and only if A has virtual members, unfortunately there's no portable method to check.
You can achieve something similar, however, using multiple inheritance and dynamic_cast, which allows cross-casting between subobjects.
You can add pointer to A inside some_t (of course if some_t is struct or class)
like this:
struct some_t
{
A *a;
...
};
void test(some_t& x)
{
if( x.a )
{
// do some
}
else
throw ...
}
If you can modify struct A and its constructor and if you can ensure the structure packing, you can add a value directly after t which holds some magic key.
struct A {
...
some_t t
struct magic_t
{
uint32 code
some_t* pt;
} magic;
}
#define MAGICCODE 0xC0DEC0DE //or something else unique
In A's constructor, do:
this->magic.code = MAGICCODE; this->magic.pt = &(this->t);
Then you can write
bool test(some_t *t) //note `*` not `&`
{
struct magic_t* pm = (struct magic_t*)(t+1);
return (pm->pt == t && pm->code == MAGICCODE);
}
This answer does not meet all the requirements of the original question, I had deleted it, but the OP requested I post it. It shows how under very specific conditions you can calculate the instance pointer from a pointer to a member variable.
You shouldn't, but you can:
#include <iostream>
#include <cstddef>
using namespace std;
struct A
{
int x;
int y;
};
struct A* find_A_ptr_from_y(int* y)
{
int o = offsetof(struct A, y);
return (struct A*)((char *)y - o);
}
int main(int argc, const char* argv[])
{
struct A a1;
struct A* a2 = new struct A;
cout << "Address of a1 is " << &a1 << endl;
cout << "Address of a2 is " << a2 << endl;
struct A *pa1 = find_A_ptr_from_y(&a1.y);
struct A *pa2 = find_A_ptr_from_y(&(a2->y));
cout << "Address of a1 (recovered) is " << pa1 << endl;
cout << "Address of a2 (recovered) is " << pa2 << endl;
}
Output
Address of a1 is 0x7fff5fbff9d0
Address of a2 is 0x100100080
Address of a1 (recovered) is 0x7fff5fbff9d0
Address of a2 (recovered) is 0x100100080
Caveats: if what you pass to find_A_ptr_from_y is not a pointer to (struct A).y you well get total rubbish.
You should (almost) never do this. See comment by DasBoot below.
It's not quite clear to me what you are trying to do, but if you are want to find the pointer to an instance of struct A when you know the pointer to a member of A, you can do that.
See for example the container_of macro in the linux kernel.
The parameter x of function test() need not be a member of any class as far as test() is converned.
If semantically in a particular application x must always be a member of a class then that information could be provided, either by passing an additional paraemter or having some_t itself contain such information. However to do that would be enturely unnecessary since if test() truely needed access to the object containing x, then why not simply pass the parent object itself? Or just make test() a member function of the same class and pass no paraemeters whatsoever? If the reason is because x may belong to differnt classes, then polymorphism can be employed to resolve that issue.
Basically I suggest that there is no situation where you would need such a capability that cannot be solved in a simpler, safer and more object oriented manner.