Sorry I ill formed the question earlier. The piece of code is something like:
class Bar
{
public:
// some stuff
private:
struct Foo
{
std::unordered_map<std::string, std::unique_ptr<Foo>> subFoo;
// some other basic variables here
};
Foo foo;
};
I got the basic idea about subFoo. But I am wondering that a single instance of Bar will contain only a single instance of Foo that is foo member variable? So a single instance/object of Bar will not be able to map multiple Foo inside the subFoo?
It feels like I am missing something here, can anyone break it down for me?
There are more misunderstandings about nested class definitions than there are actual benefits. In your code it really does not matter much and we can change it to:
struct Foo {
std::unordered_map<std::string, std::unique_ptr<Foo>> subFoo;
// some other basic variables here
};
class Bar
{
Foo foo;
};
Foo is now defined in a different scope and it is no longer private to Bar. Otherwise it makes no difference for the present code.
I am wondering that a single instance of Bar will contain only a single instance of Foo that is foo member variable?
Yes.
So a single instance/object of Bar will not be able to map multiple Foo inside the subFoo?
subFoo is a map holding unique pointers to Foos. Bar::foo is not managed by a unique pointer, hence placing them in subFoo is not possible without running into a double free error. std::unique_ptr can be used with a custom deleter, but thats not the case here. Hence you cannot store a unique pointer to Bar::foo in any Foo::subFoo. You can however, store unique pointers to other Foos in Foo::subFoo.
Related
In the code below, I get a compiler error when trying to push fooBaz onto v. This surpises me since Baz is a derived class of Bar.
Why is this not allowed, and what can I do if want to put several Foo instances, templated on classes derived from the same base class, into a vector?
#include <iostream>
#include <vector>
template<typename T>
class Foo {};
struct Bar {};
struct Baz : public Bar {};
int main() {
Foo<Bar> fooBar;
Foo<Baz> fooBaz;
std::vector<Foo<Bar>> v;
v.push_back(fooBar);
v.push_back(fooBaz);
return 0;
}
Java Generics are not the same kind of thing as C++ templates.
C++ values of class type are not the same thing as Java reference variables of class type.
You are running into both problems here.
C++ templates generate a new, unrelated type for each set of template arguments. You can create a common base, but you have to do it yourself.
Java Generics, under the hood, actually create a single class. It then writes casting operations at inputs and outputs.
So a Java Generic, Foo<Base> and Foo<Derived> are related, because the the Java Generic actually creates a Foo<Object> then wraps it up in casts, and those casts in Foo<Base> and Foo<Derived> are compatible. (well, not always Object, you mark up the generic arguments with information that Java uses to determine what the actual type it writes its Generic for, but that gives you the idea).
In C++, there is no relation. (well, template pattern matching gives you a compile-time relation, but no runtime relation at all)
The second problem is that you are treating values of class type like references. In C++, a Foo is an actual foo. It represents a block of memory that is an instance of that class. In Java, a Foo is a smart pointer to an object on the heap somewhere that obeys the Foo protocol (is a derived class).
You cannot easily make a value of type Foo in Java, and you cannot easily make a mark and sweep smart pointer to a Foo in C++.
Foo<Bar> fooBar;
Foo<Baz> fooBaz;
these are two unrelated types. They are stored on the stack (automatic storage).
std::vector<Foo<Bar>> v;
This stores a buffer of memory containing Foo<Bar> objects packed together.
v.push_back(fooBar);
This copies a fooBar instance from automatic storage into the vector.
v.push_back(fooBaz);
This doesn't work, because fooBar and fooBaz are unrelated types.
Now, prior to c++23 reflection, mimicing what Java does is difficult in C++. You have to do some steps manually.
First, instruct Foo to understand inheritance when told so manually:
struct empty_t {};
template<class T, class Base=empty_t>
class Foo:Foo<Base> {};
template<>
class Foo<empty_t, empty_t> {
virtual ~Foo() {}
};
struct Bar {};
struct Baz : public Bar {};
auto fooBar = std::make_unique<Foo<Bar>>();
auto fooBaz = std::make_unique<Foo<Baz, Bar>>();
std::vector<std::unique_ptr<Foo<Bar>>> v;
v.push_back(std::move(fooBar));
v.push_back(std::move(fooBaz));
this compiles.
In c++23 compile time reflection should let you auto-detect the base classes of Baz and have Foo<Baz> automatically inherit from Foo<Bases>... if you want.
Now, inheritance is only one kind of way to handle polymorphism in C++, but I think is enough for today.
As mentioned in a comment, templates are like recipes. You need to instantiate a class template to get a class, before it is just a template. There is no implicit relation between different instantiations (other than being instantiations of the same template). Maybe this gets more clear when you consider following example:
template<typename T> struct Foo {};
template <> struct Foo<int> { void bar(){} };
template <> struct Foo<double> { void moo(){} };
int main() {
Foo<int> x;
x.bar();
Foo<double> y;
y.moo();
}
Foo<int> and Foo<double> are two unrelated types with completely different methods. If they were not instantiations of a template, but "ordinary" types with different members you would not be surprised that you cannot push a FooA into a std::vector<FooB>.
A std::vector<Foo<Bar>> can only hold elements of type Foo<Bar>. The vector is not aware that this type is the result of instantiating the template Foo. And even if it was, you cannot assign a Foo<Bar> to a Foo<Baz> unless you provide a conversion.
Actually there is more to your misunderstanding that needs to be debunked. Suppose you have a std::vector<Bar> then you also cannot push a Baz to that vector. See here for why not: What is object slicing?. And here for what to do instead: https://stackoverflow.com/a/16126649/4117728.
I think I might have an oddly specific/weird question that I might be making more complex then it needs to be.
I have a simple class:
class Foo{
public:
struct Bar{
int otherdata;
};
int somedata;
};
In another file I import this class and create an Instance of Foo
I also want to create a vector of type Bar..how would I do this?
I have tried:
//Assume I already imported proper prereqs
int main() {
Foo test;
vector<test::Bar> vec;
//or
vector<test.Bar> vec;
//or
vector<Bar> vec;
}
Whats the best way to do this? I can simply do this if I take the struct and place it outside the class..but is there a way to encapsulate the struct and create a vector of that type of struct. I should point out that I do not want to initialize the vector inside the class, but rather in my main function.
Like this:
vector<Foo::Bar> vec;
You're looking for vector<Foo::Bar>.
The structure/class Bar will always have one int regardless of the instance of Foo, so it makes no sense (or at least it's redundant) to qualify it with test as in test::Bar or test.Bar. Hence, we qualify it as Foo::Bar.
In C++:
I have an object I'll call Foo.
Foo performs statistical operations on a supplied data set. The first step of the process involves a fitting function, and a functional parameter can be supplied so that the user can specify the type of model being used.
The problem is that I now have a situation where the function parameter needs to have access to data that does not exist in Foo but rather in the object that is using Foo, which I will call Bar.
So Bar calls Foo to have Foo operate on Bar's data. Bar has a specific function it wants to use as the functional parameter but this function requires information specific to Bar.
I don't want to pass Bar because if I code Foo up to receive Bar, then every time I have a new object that needs additional info passed to Foo, I will have to adjust the Foo class to accept that object.
I don't want to modify the functional parameter input in Foo because then I'll have to modify the functional parameter input for every new usage case as well.
I considered using a base class I'll call StandardFunc. Then, via virtual methods, Bar could create an object called ModifiedFunc that derives from StandardFunc. It could override the StandardFunc's function and also supply the additional info as class parameters. This doesn't work either because to avoid slicing I have to type-cast ModifiedFunc to StandardFunc. This means that inside Foo I have to change the type-cast line for every new object name.
Can someone please point me in the right direction for how I can allow users to pass either a functional parameter alongside arbitrary parameters the function requires without having to recode the Foo class for every different usage case? I'm really stuck on this.
EDIT: pseudo code example:
class Foo
{
void processHandler(function)
void process();
void process(function);
void theUsualFunction(vector); //the default function used by process
vector vec;
};
void Foo::process()
{
processHandler(theUsualFunction);
}
void Foo::process(function f)
{
processHandler(f)
}
void Foo::processHandler(function f)
{
f(vec)
//do other stuff to vec
}
void Foo::theUsualFunction(vector v)
{
//default vec processor
}
class Bar
{
int x;
int y;
vector vec;
void theModifiedFunction(vector);
void callFooToProcess();
};
void Bar::theModifiedFunction(vector v)
{
//process v, but in a way that requires x and y
}
void Bar::callFooToProcess()
{
Foo foo;
foo.setVector(vec);
process(theModifiedFunction);
}
So this code is kind of an example of what I want to achieve, but it doesn't work as written. The reason is because I have no way of getting Bar::x and Bar::y to the function Foo::processHandler(function) without modifying the arguments for Foo::processHandler, and I don't want to do that because then every new class like Bar and every new theModifiedFunction that requires different data will require me to rewrite the arguments for processHandler.
This doesn't work either because to avoid slicing I have to type-cast ModifiedFunc to StandardFunc.
Slicing only occurs if you pass the argument by value. You should pass it as a pointer, that's how polymorphism is supposed to work.
Also, you can keep passing the argument by value if you make your class a template:
template<class Func>
class Foo {
void doStuff(Func func) {
...
}
}
Keep in mind though, that in this case Func has to be known at compile-time.
Although there may be other ways of handling this situation, I would suggest considering to have Bar contain Foo. This is called a has-a relationship [wiki]. The advantage of this is that you can use Foo as-is without modifying anything within Foo, as well as Bar need not pass around its private data. Hope the following code snippet would help you to understand the concept.
public class Bar
{
private Foo myFoo;
private int myInfo;
void a()
{
myFoo.doStuff(myInfo);
}
}
We all are familiar with the concept of encapsulation and abstraction but sometimes this may lead to an obstacle I'm curious about the tricks or methods or whatever you call them to solve the problem.
here we have a nested c++ class:
#include <iostream>
using namespace std;
class Foo {
public:
int get_foo_var()
{
return foo_var;
}
void set_foo_var(int a)
{
foo_var = a;
}
private:
int foo_var;
};
class Bar {
public:
Foo get_foo()
{
return foo;
}
private:
Foo foo;
};
int main()
{
Bar bar;
bar.get_foo().set_foo_var(2);
cout << bar.get_foo().get_foo_var() << endl;
}
as you see here, get_foo() returns a copy of foo_var(it's value) which means it is not the reference to the original one and changing it does nothing, thus nothing is changed.
one solution might be changing to get_foo() in a way that returns a reference and not a value but this is of course in contrast with the concept of encapsulation.
what are the solutions to solve this problem without breaking software designing principles?
UPDATE
one pointed out setting foo_var by a function in bar class:
class Bar {
public:
void set_foo_var(int a) {
foo.set_foo_var(a);
}
private:
Foo foo;
};
but I think this violates encapsulation and abstraction! the whole concept of abstraction is if "foo" is related to "Foo" and "bar" is related to "Bar", that most of foo manipulations should be done in Foo class and some manipulations can be applied in other classes. what about the first situtation? (the situtation in which foo manipulation has nothing to do with Bar and so manipulating foo in bar is stupid!)
Whether you want to return a copy of or a reference to something is a high-level design decision. Both ways can be required, depending on the context.
In this particular example, you could add a corresponding method in Bar to modify the Foo behind it:
class Bar {
public:
void set_foo_var(int a) {
foo.set_foo_var(a);
}
private:
Foo foo;
};
Is this good or bad? The answer is: we cannot tell you. Generally, it's hard to seriously talk about good class design with names like "Foo" and "Bar". What's good and bad depends on the actual, real usage scenario! :)
Let's look at this from a purely conceptual level for a minute. This what your design says:
There exists one conceptual Foo entity for every Bar instance (because I can get a Foo from a Bar, and its state depends on which Bar I get it from).
Each Foo instance belongs to the Bar instance it came from (because operations on a Foo change the Bar it came from - the next time I ask for a Foo from a Bar, the previous Foo's changes are reflected).
A Foo has the same lifetime as its Bar (because I can ask for it at any time in the Bar's lifetime, I can use it as long as Bar exists, and the caller of get_foo() does not manage the lifetime of the returned Foo object).
Another way of looking at it is that Foo is already designed as part of Bar's internal state, a "conceptual member variable", regardless of whether it is actually implemented that way.
Given what your public interface is already telling you, how does returning a non-const reference to a private member really break encapsulation? Could you change the implementation so that Foo isn't a private member variable, yet still use the same public interface? Yes, you could. The only implementation changes that would force you to change the public interface ALSO force you to change the conceptual interface described above.
Implementation rules of thumb can be over-applied. Move past mechanics and look at conceptual design instead. Assuming you're OK with what your design is implying, in this case I say that returning a reference to a private member variable does NOT break encapsulation. At least that's my take on it.
An alternative is to have Foo and Bar less tightly coupled.
class Bar {
public:
Foo get_foo()
{
return foo;
}
set_foo(Foo new_foo)
{
// Update foo with new_foo's values
foo = new_foo;
}
private:
Foo foo;
};
In this case, Foo reflects some part of Bar's internal state at the time it was requested, but isn't tied to the Bar it came from. You have to explicitly call set_foo() to update Bar. Without that requirement, Foo really is conceptually a member variable regardless of how you implement it.
How would you call the constructor of the following class in these three situations: Global objects, arrays of objects, and objects contained in another class/struct?
The class with the constructor (used in all three examples):
class Foo {
public:
Foo(int a) { b = a; }
private:
int b;
};
And here are my attempts at calling this constructor:
Global objects
Foo global_foo(3); // works, but I can't control when the constructor is called.
int main() {
// ...
}
Arrays of objects
int main() {
// Array on stack
Foo array_of_foos[30](3); // doesn't work
// Array on heap
Foo *pointer_to_another_array = new Foo(3) [30]; // doesn't work
}
There I'm attempting to call the constructor for all elements of the arrays, but I'd also like to know how to call it on individual elements.
Objects contained in classes/structs
class Bar {
Foo foo(3); // doesn't work
};
int main() {
Bar bar;
}
Global objects
Yours is the only way. On the other hand, try to avoid this. It’s better to use functions (or even other objects) as factories instead. That way, you can control the time of creation.
Arrays of objects
There’s no way to do this directly. Non-POD objects will always be default-constructed. std::fill is often a great help. You might also want to look into allocators and std::uninitialized_fill.
Objects contained in classes/structs
Use initialization lists in your constructor:
class Bar {
Foo foo;
Bar() : foo(3) { }
};
Static members must actually be defined outside the class:
class Bar {
static Foo foo;
};
Foo Bar::foo(3);
To correct some misconceptions about globals:
The order is well defined within a compilation unit.
It is the same as the order of definition
The order across compilation units is undefined.
The order of destruction is the EXACT opposite of creation.
Not something I recommend but: So a simple solution is to to put all globals into a single compilation unit.
Alternatively you can tweak the use of function static variables.
Basically you can have a function the returns a reference to the global you want (defining the global inside the function). It will be created on first use (and destroyed in reverse order of creation).
Foo& getGlobalA() // passed parameters can be passed to constructor
{
static Foo A;
return A;
}
Foo& getGlobalB()
{
static Foo B;
return B;
}
etc.
The Konrad reply is OK, just a puntualization about the arrays....
There is a way to create an array of items(not pointers) and here it follows:
//allocate raw memory for our array
void *rawMemory = operator new[](30 * sizeof(Foo))
// point array_of_foos to this memory so we can use it as an array of Foo
Foo *array_of_foos = static_cast<Foo *>(rawMemory);
// and now we can create the array of objects(NOT pointers to the objects)
// using the buffered new operator
for (int i = 0; i < 30; i++)
new(array_of_foos[i])Foo(3);
This approach is described here: http://www.amazon.com/gp/product/0321334876?ie=UTF8&tag=aristeia.com-20&linkCode=as2&camp=1789&creative=9325&creativeASIN=0321334876
For the global case there is no way to control when it is called. The C++ spec essentially says it will be called before main() and will be destroyed sometime afterwards. Other than that' the compiler is free to do as it pleases.
In the first array case you are creating a static array of Foo objects. By default each value in the array will be initialized with the default constructor of Foo(). There is no way with a raw C++ array to force a particular overloaded constructor to be called. You can infer a bit of control by switching to a vector instead of an array. The vector constructor has an overloaded constructor vector(size,defaultValue) which should achieve what you are looking for. But in this case you must be careful because instead of calling Foo(3) it will call Foo(const Foo& other) where other is Foo(3).
The second array case is very similar to the first case. The only real difference is where the memory is allocated (on the heap instead of the stack). It has the same limitation with regards to calling to the constructor.
The contained case is a different issue. C++ has a clear separation between the definition of a field within an object and the initialization of the field. To get this to work in C++ you'll need to change your Bar definition to the following
class Bar{
Foo foo;
Bar() : foo(3){}
};
There seems to be the general gist in this thread that you cannot initialize members of an array other than using the default constructor. One answer even creates another type, just to call another constructor. Even though you can (if the array is not part as a member of a class!):
struct foo {
foo(int a): a(a) { }
explicit foo(std::string s): s(s) { }
private:
int a;
std::string s;
};
/* global */
foo f[] = { foo("global"), foo("array") };
int main() {
/* local */
foo f[] = { 10, 20, 30, foo("a"), foo("b") };
}
The type, however, needs to be copy-able: The items given are copy-initialized into the members of the array.
For arrays as members in classes, it's the best to use containers currently:
struct bar {
/* create a vector of 100 foo's, initialized with "initial" */
bar(): f(100, foo("initial")) { }
private:
std::vector<foo> f;
};
Using the placement-new technique described by andy.gurin is an option too. But note it will complicate things. You will have to call destructors yourself. And if any constructor throws, while you are still building up the array, then you need to figure where you stopped... Altogether, if you want to have arrays in your class, and want to initialize them, use of a std::vector is a simple bet.
Construction of arrays of objects:
You can modify your original example by using default parameters.
Currently only the default constructor is supported.
This is something that is being addressed by the next version (because everybody asks this question)
C++0X initializer lists solve this problem for the arrays of objects case. See this Herb Sutter blog entry, where he describes them in detail.
In the meantime you might be able to work around the problem like so:
class Foo {
public:
Foo(int a) : b(a) {}
private:
int b;
};
class Foo_3 : public Foo {
public:
Foo_3() : Foo(3) {}
};
Foo_3 array_of_foos[30];
Here, the Foo_3 class exists solely for the purpose of calling the Foo constructor with the correct argument. You could make it a template even:
template <int i>
class Foo_n : public Foo {
public:
Foo_n() : Foo(i) {}
};
Foo_n<3> array_of_foos[30];
Again this might not do exactly what you want but may provide some food for thought.
(Also note that in your Foo class you really should get into the habit of using member initializer lists instead of assignments in the constructor, as per my example above)
I reckon there are two ways to make sure global class objects' constructors are called safely at the time of their "creation":
Declare them in a namespace and make that namespace globally accessible.
Make it a global pointer to the class object and assign a new class object to it in main(), granted code for other global objects' constructors that access the object will execute before this.
Just my two cents.