I am totally new to c++ and thought it would be good practice to write a program which solved a given liter puzzle (you have 2 containers with capacities of 3 and 5 liters, can you obtain 4 liters? etc.)
I wrote a class for a given container and a function which was intended to 'pour' the contents of one container into another. The function doesn't change the value of the contents of any object however, despite the entire class being public. I'm not sure what I'm doing wrong.
Here is my code:
#include <iostream>
using namespace std;
class Container {
public:
int quantity; //quantity of water in container
int size; //max amt of water
};
void pour(Container a, Container b) {
int differential = b.size - b.quantity;
if (a.quantity <= differential) {
b.quantity = a.quantity + b.quantity;
a.quantity = 0;
}
else if (a.quantity > differential) {
b.quantity = b.quantity - differential;
a.quantity = a.quantity - differential;
}
};
int main() {
Container bottle1;
bottle1.quantity = 5;
bottle1.size = 6;
Container bottle2;
bottle2.quantity = 0;
bottle2.size = 2;
pour(bottle2, bottle1);
cout << bottle1.quantity << ", " << bottle2.quantity << endl;
return 0;
}
I'm sure my mistake is obvious but I can't find an answer anywhere. Any help would be greatly appreciated.
You're passing the Containers as copies. This means that the containers you alter in the pour function are destructed upon function exit.
The solution is to use references:
void pour(Container& a, Container& b)
The & after the type denotes a reference. This means that, instead of copies of a and b being used inside pour, the function gets access to the same a and b as the caller.
This is probably because you're passing the objects by value. You'll want to pass them by reference. You can do this by changing your method header.
Essentially, each instance of Container in the method header should become Container&. The call will not need to be changed.
You can also pass pointers. Your arguments would then become Container *a, and in your call you'd have to add an ampersand (&) before each variable name (e.g. a becomes &a). You'd then also have to change any derefs of the object from periods (.) to arrows (->).
Your method would become:
void pour(Container *a, Container *b) {
int differential = b->size - b->quantity;
if (a->quantity <= differential) {
b->quantity = a->quantity + b->quantity;
a->quantity = 0;
}
else if (a->quantity > differential) {
b->quantity = b->quantity - differential;
a->quantity = a->quantity - differential;
}
};
I mentioned both because in some cases, the designers of a program will adopt the convention that all references are const references. That is, any object passed by reference is not to be modified (which is enforced by using the const keyword before the type name in a method header), and that all other objects are passed by pointer. This makes it more clear, in the function call, whether or not an argument will be modified.
The choice of using a const reference over pass-by-value in that convention is to improve the efficiency of a function call. It is quicker to pass a reference than to make a copy of an object.
Related
I am trying to implement this POMDP solver with given examples for my decision making problem and I followed the documentation in the repository to build different relevant classes and functions in the header file
class SimpleState: public State {
public:
int position;
int context;
int time;
SimpleState();
SimpleState(int _position, int _context, int _time) :
rat_position(_position),
context(_context),
time(_time) {
}
SimpleState(int _state_id);
~SimpleState();
std::string text() const;
};
SimpleState::SimpleState() {
}
class StarMazeProblem : public DSPOMDP,
public MDP {
protected:
std::vector<std::vector<std::vector<State> > > transition_probabilities_; //state, action, [state, weight]
mutable MemoryPool<SimpleState> memory_pool_;
std::vector<SimpleState*> states_;
mutable std::vector<ValuedAction> mdp_policy_;
public:
enum {CENTER = 0, RIGHT = 1, LEFT = 2};
public:
StarMazeProblem();
int NumStates() const;
void ComputeDefaultActions(std::string type) const;
ParticleUpperBound* CreateParticleUpperBound(std::string name = "DEFAULT") const;//?
ScenarioUpperBound* CreateScenarioUpperBound(std::string name = "DEFAULT",
std::string particle_bound_name = "DEFAULT") const;
ScenarioLowerBound* CreateScenarioLowerBound(std::string name = "DEFAULT",
std::string particle_bound_name = "DEFAULT") const;
}
and in the starmaze.cpp file the relevant lines are
int StarMazeProblem::NumStates() const {
return CONTEXT * POSITIONS * TIME;
}
void StarMazeProblem::ComputeDefaultActions(string type) const {
cerr << "Default action = " << type << endl;
if (type == "MDP") {
const_cast<StarMazeProblem*>(this)->ComputeOptimalPolicyUsingVI();
int num_states = NumStates();
default_action_.resize(num_states);
double value = 0;
for (int s = 0; s < num_states; s++) {
default_action_[s] = policy_[s].action;
value += policy_[s].value;
}
} else {
cerr << "Unsupported default action type " << type << endl;
exit(0);
}
}
ScenarioLowerBound* StarMazeProblem::CreateScenarioLowerBound(string name,
string particle_bound_name="DEFAULT") const {
const DSPOMDP* model = this;
const StateIndexer* indexer = this;
const StatePolicy* policy = this;
ScenarioLowerBound* bound = NULL;
if (name == "TRIVIAL" ) {
bound = new TrivialParticleLowerBound(this);
} else if (name == "RANDOM") {
bound = new RandomPolicy(this,
CreateParticleLowerBound(particle_bound_name));
} else if (name == "MODE" || name == "DEFAULT") {
ComputeDefaultActions("MDP");
bound = new ModeStatePolicy(model, *indexer, *policy,
CreateParticleLowerBound(particle_bound_name));
} else {
cerr << "Unsupported scenario lower bound: " << name << endl;
exit(1);
}
return bound;
}
here I got the following error for the above code:
src/starmaze.cpp:301:36: error: passing 'const std::vector<int>' as 'this' argument discards qualifiers [-fpermissive]
default_action_.resize(num_states);
^
In file included from /opt/local/include/gcc7/c++/vector:64:0,
from ../../../include/despot/interface/lower_bound.h:4,
from ../../../include/despot/core/builtin_lower_bounds.h:4,
from src/starmaze.h:3,
from src/starmaze.cpp:1:
/opt/local/include/gcc7/c++/bits/stl_vector.h:689:7: note: in call to 'void std::vector<_Tp, _Alloc>::resize(std::vector<_Tp, _Alloc>::size_type) [with _Tp = int; _Alloc = std::allocator<int>; std::vector<_Tp, _Alloc>::size_type = long unsigned int]'
resize(size_type __new_size)
^~~~~~
I have basic c++ knowledge and I could not figure out the reason for the error since I followed the examples. Any suggestion?
Important to know before reading
I've looked over this code several times, and cannot find where default_action_ is declared as a const std::vector<int>. This leads me to assume (based on the fact that the compiler recognizes it as such) that the variable is declared in one of the parent classes: public DSPOMDP, public MDP.
You are trying to modify a const vector<int>
This issue is pretty straight-forward.
You cannot change a const std::vector<Ty>
The whole point of making something const is to prevent the programmer from changing it.
Whatever you are trying to do here, you should consider copying the vector data into a new vector, and make the changes to it in the copy.
Okay so let's say you decided to do the naughty deed and remove const from the *.h file wherever it may be. You'll still have an issue (see below)
You are trying to modify the class instance from a const method
This is if you removed const from the vector
The default_action_.resize(num_states); is going to cause the compiler to yell at you.
The issue here is now your method StarMazeProblem::ComputeDefaultActions() is specified as const. This means you cannot change your class instance in any way from within that function/class method. What you are doing is modifying the default_action_ vector by calling resize() on it. This inevitably changes the class instance which is forbidden because your method is declared const and your default_action_ vector is declared somewhere in your class hierarchy. Additionally you are changing the vector directly by assigning it to an rvalue (See code below)
int num_states = NumStates();
default_action_.resize(num_states); // <---- default_action_ cannot be modified
for (int s = 0; s < num_states; s++) {
default_action_[s] = policy_[s].action; // <---- default_action_ cannot be modified
value += policy_[s].value;
}
Solution
You need a copy of the vector you are trying to modify. Going into h files and changing them without knowing 100% exactly what you are doing is never the answer.
Making a temporary vector in the class method, copying the data to it, and manipulating the copy is completely allowed and will not give you any compiler errors; however, this approach may completely avoid your official goal. It looks like you are really trying to change the default_action_ vector and that almost seems like your true goal here.
It's hard for me to give you a definitive answer on this specific topic. Mainly because I do not know what this entire class hierarchy does or what it is for exactly (I briefly looked over the code in the link provided.)
What you'll need to do ultimately is determine why you are trying to change that vector, and why it was made const by the original developers. Then you can determine if there is a better way other than explicitly removing the constness of the vector.
If you are still trying to make changes to the class instance read below
This solution part has to do with the qualifier of the class you are dealing with.
You can either remove the constant qualifier from the class method if it is absolutely necessary to make changes to the class instance from within that method.
OR
Find an alternative method for what you are trying to do, and break it up into multiple method calls on the class instance.
You've made ComputeDefaultActions() const-qualified, but there is very little that says that it should be.
It calls ComputeOptimalPolicyUsingVI() which is not const-qualified since it changes the internal state of *this. You've worked around that by casting away const on this - but that function resizes policy_ to also be NumStates() big which ComputeDefaultActions() depends on - otherwise the internal loop would be very dangerous.
It changes default_action_ by resizeing it and by assigning its elements. This may be a mistake, if the computation made is actually meant to not change *this but ... (see next bullet)
It doesn't return anything. Everything the function does is to change the internal state of *this. The computed value is just dropped at the end of the calculation and it's not even used internally in the function. Either make the function return value or remove value completely.
Suggested changes:
#include <algorithm>
#include <stdexcept>
void StarMazeProblem::ComputeDefaultActions(string type) { // non-const
cerr << "Default action = " << type << endl;
if (type == "MDP") {
ComputeOptimalPolicyUsingVI(); // no casting needed
default_action_.resize(policy_.size()); // dependency made clear
// Use the standard transform function:
std::transform(policy_.begin(), policy_.end(), default_action_.begin(),
[](const auto& p) { return p.action; });
} else {
// friendlier than exit():
throw std::runtime_error("Unsupported default action type " + type);
}
}
I have an int member named size within my blob class whose value I am attempting to change within a method. Initially, I tried...
void blob::make_union(blob parent_blob){
parent=&parent_blob;
parent_blob.size = parent_size
}
Then I tried making a function whose sole purpose was to change the size value. Its worth noting that it changes the values within the function as verified by some cout statements.
int blob::change_size(int dat_size){
size=size+dat_size;
return this.size;
}
after making the new method change my other method
'void blob::make_union(blob parent_blob){
parent=&parent_blob;
int temp = size;
parent_blob.size = parent_blob.change_size(temp);
}'
still no dice. The following within main function does work.
if (charmatrix[m-1][n-1]==charmatrix[m][n]){
blobmatrix[m][n].make_union(blobmatrix[m-1][n-1]);
blobmatrix[m-1][n-1].size=blobmatrix[m-1][n-1].size + blobmatrix[m][n].size;
What am I doing wrong?
You are passing your blob class by value: you are making a copy of your blob object, and that is what the function change_size is working with.
void increment_number(int i) { ++i; }
void increment_number_ref(int& i) { ++i; }
int main()
{
int n = 6;
// This takes a copy of the number, and increments that number, not the one passed in!
increment_number(n);
// n == 6
// This passed our object by reference. No copy is made, so the function works with the correct object.
increment_number_ref(n);
// n == 7
return 0;
}
You need to pass your blob by reference (or as a pointer) if you wish to modify that object's value: see above.
In languages that have pass by reference and pass by value - if you have a situation where you make a change, and then suddenly the change is 'gone', you're almost certainly passing a copy vs a reference.
Try changing the prototype to pass in the blob by reference.
I am trying to create an object and everytime I create an object, I then store that object in a static class variable that is an array of all of the objects created.
I am new to c++ and have no idea how to accomplish this. I have done it in Java before, but I am stuck here.
Take this for example purposes:
class Rectangle
{
private:
int width;
int length;
// Code to create an array of Rectangle Objects
// that hold all the the Rectangles ever created
public:
Rectangle();
Rectangle(int x, int y);
};
Rectangle::Rectangle()
{
width = 0;
length = 0;
// code to add an instance of this object to an array of Rectangle Objects
}
Rectangle::Rectangle(int x, int y)
{
width = x;
length = y;
// code to add an instance of this object to an array of Rectangle Objects
}
Is this possible?
Since you have to use an array to keep all objects you have to define a constant maximum size, since the size of an array is fixed and cannot be changed. This means that you also have to define a variable that keeps track of how many elements the array has, so that you don't exceed its boundaries.
const int MAX_SIZE = 100;
class Rectangle
{
private:
int width;
int length;
static Rectangle* all_rectangles[MAX_SIZE];
static int rectangle_count;
public:
Rectangle();
Rectangle(int x, int y);
};
Then you define the static variable and add the objects to the array in the Rectangle constructor, for example:
//Define static variables
Rectangle* Rectangle::all_rectangles[MAX_SIZE];
int Rectangle::rectangle_count = 0;
//Constructor
Rectangle::Rectangle () {
all_rectangles[rectangle_count] = this;
rectangle_count++;
}
Since the array with rectangles (and its components) is private, you can only reach it from within the class. You can however define functions that are public, to reach the rectangles private variables. You can get the width of a rectangle by declaring a function
static int getWidth(int a){
return all_rectangles[a]->width;
}
and call it by cout << Rectangle::getWidth(2) // Get width of second element in array
However vectors are preferable to use before arrays since they are expandable and includes many build-in functions, such as add and remove elements.
Nowadays we tend to avoid plain array and normal pointers.
So go for smart pointers and STL containers.
As your objects will live and die, a vector may not be soon sparse, having lots of holes corresponding to the (deleted) objects you do not use anymore.
Another solution would be an unordered map (hash table). We then need a key. We will not think about transforming the value of a (the this) pointer to a int or long as it is a very dangerous way to go.
So we must pay for some unique id ( see boost uuid ). This is also costly for the computing time but all this mechanism will save you time ( for writing code documentation ).
We then need a smart pointer.
As you want to keep track of all the object created we will go for a mandatory "factory" function to create your objects. As they may not be uniquely owned the only choice left for the factory function is to reject a shared pointer.
This is not directly a shared pointer that may be stored inside our container as it would prevent us to easily get rid of the object once not needed anymore ( the shared pointer inside the container would still participate to the object count ).
Shared pointer may get a custom deleter that will let us do some housekeeping for the container
So this is a weak pointer ( that do not participate to the object count ( or in some very small extent( weak count ) ) that is chosen for our container.
Here is some code ( forgive me I chose widget and not rectangle ):
Our class that must inherit from this curious class ( e.g see Scott Meyers new book Effective Modern C++ item 19 )
class widget:public std::enable_shared_from_this<widget>
alias ( ~ typedef )
using widget_weakptr_cont_t = std::unordered_map<std::string,std::weak_ptr<widget>>;
using widget_smrtp_t = std::shared_ptr<widget>;
using uuid_t = boost::uuids::uuid;
The factory function
static widget_smrtp_t widget_factory(void);
The container
static widget_weakptr_cont_t widget_cont;
The constructor is private ( you may also prevent all the other form of copy or move construction to strengthen the rule )
private:
widget();
void self_emplace(void);
const uuid_t uuid_tag;
The custom deleter for the shared pointers
auto widgetDeleter = [](widget* pw) {
std::cout << "Widget deleter" << std::endl;
widget::widget_cont.erase(pw->uuid_to_string());
delete pw;
if ( widget::widget_cont.empty() )
std::cout << "No Widget left" << std::endl; };
The factory function
widget::widget_smrtp_t widget::widget_factory(void)
{
auto wshp = widget_smrtp_t(new widget(),widgetDeleter);
wshp->self_emplace();
return wshp;
}
The self_emplace function
void widget::self_emplace(void)
{
widget::widget_cont.emplace(uuid_to_string(),shared_from_this());
}
You may then use your factory function inside some other functions ( or main( ) )
auto pw = widget::widget_factory();
An example for retrieving our object from the container could be
for ( auto const & it : widget::widget_cont )
{
//if interested by uuid we normally do
// std::cout << it.first << std::endl;
//For exercice we do the following:
auto shp = it.second.lock();
if ( shp )
{
std::cout << shp->uuid_to_string() << std::endl;
}
}
In the execution below the function func ( not displayed here the post is already too long )
only makes a copy of a globally factored shared pointer (to one of our widget).
The container is not modified by what happened inside func.
func2 creates another local widget that is destroyed when leaving func2. container is shown at these 2 steps.
Finally the globally constructed widget is only destroyed at the end (of the main )
Hello world!
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
func
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
func2
Widget elems are:
b2aedb78-8bb0-427e-9ada-fce37384f7de
84871b52-0757-44c1-be23-fb83e69468c0
Widget deleter
Widget elems are:
84871b52-0757-44c1-be23-fb83e69468c0
bye !
Widget deleter
No Widget left
I hope all of this may help
NGI
EDIT 2016.08.21
I publish the "unabridged code" Code on Coliru
It will not be much clearer because when I first replied I tried also other syntax features just for test.
Anyway you have now all in hands ( sometimes I do not publish a full code in order to avoid the "homework" copy/paste problem )
Lately I tried to simplify my code without success, 2 thoughts:
class widget:public std::enable_shared_from_this < widget > { ... }; is already a CRTP
You can not use shared_from_this() when there is no shared_ptr < T > already existing SO: shared_from_this() causing bad_weak_ptr exception
Lately I'm writing my getter and setters as (note: real classes do more things in getter/setter):
struct A {
const int& value() const { return value_; } // getter
int& value() { return value_; } // getter/setter
private:
int value_;
};
which allows me to do the following:
auto a = A{2}; // non-const object a
// create copies by "default" (value always returns a ref!):
int b = a.value(); // b = 2, is a copy of value :)
auto c = a.value(); // c = 2, is a copy of value :)
// create references explicitly:
auto& d = a.value(); // d is a ref to a.value_ :)
decltype(a.value()) e = a.value(); // e is a ref to a.value_ :)
a.value() = 3; // sets a.value_ = 3 :)
cout << b << " " << c << " " << d << " " << e << endl; // 2 2 3 3
const auto ca = A{1};
const auto& f = ca.value(); // f is a const ref to ca.value_ :)
auto& g = ca.value(); // no compiler error! :(
// g = 4; // compiler error :)
decltype(ca.value()) h = ca.value(); // h is a const ref to ca.value_ :)
//ca.value() = 2; // compiler error! :)
cout << f << " " << g << " " << h << endl; // 1 1 1
This approach doesn't allow me to:
validate the input for the setter (which is a big BUT),
return by value in the const member function (because I want the compiler to catch assignment to const objects: ca.value() = 2). Update: see cluracan answer below.
However, I'm still using this a lot because
most of the time I don't need that,
this allows me to decouple the implementation details of my classes from their interface, which is just what I want.
Example:
struct A {
const int& value(const std::size_t i) const { return values_[i]; }
int& value(const std::size_t i) { return values_[i]; }
private:
std::vector<int> values_;
// Storing the values in a vector/list/etc is an implementation detail.
// - I can validate the index, but not the value :(
// - I can change the type of values, without affecting clients :)
};
Now to the questions:
Are there any other disadvantages of this approach that I'm failing to see?
Why do people prefer:
getter/setters methods with different names?
passing the value as a parameter?
just for validating input or are there any other main reasons?
Generally using accessors/mutators at all is a design smell that your class public interface is incomplete. Typically speaking you want a useful public interface that provides meaningful functionality rather than simply get/set (which is just one or two steps better than we were in C with structs and functions). Every time you want to write a mutator, and many times you want to write an accessor first just take a step back and ask yourself "do I *really* need this?".
Just idiom-wise people may not be prepared to expect such a function so it will increase a maintainer's time to grok your code.
The same-named methods are almost the same as the public member: just use a public member in that case. When the methods do two different things, name them two different things.
The "mutator" returning by non-const reference would allow for a wide variety of aliasing problems where someone stashes off an alias to the member, relying on it to exist later. By using a separate setter function you prevent people from aliasing to your private data.
This approach doesn't allow me to:
return by value in the const member function (because I want the compiler to catch assignment to const objects ca.value() = 2).
I don't get what you mean. If you mean what I think you mean - you're going to be pleasantly surprised :) Just try to have the const member return by value and see if you can do ca.value()=2...
But my main question, if you want some kind of input validation, why not use a dedicated setter and a dedicated getter
struct A {
int value() const { return value_; } // getter
void value(int v) { value_=v; } // setter
private:
int value_;
};
It will even reduce the amount typing! (by one '=') when you set. The only downside to this is that you can't pass the value by reference to a function that modifies it.
Regarding your second example after the edit, with the vector - using your getter/setter makes even more sense than your original example as you want to give access to the values (allow the user to change the values) but NOT to the vector (you don't want the user to be able to change the size of the vector).
So even though in the first example I really would recommend making the member public, in the second one it is clearly not an option, and using this form of getters / setters really is a good option if no input validation is needed.
Also, when I have classes like your second type (with the vector) I like giving access to the begin and end iterators. This allows more flexibility of using the data with standard tools (while still not allowing the user to change the vector size, and allowing easy change in container type)
Another bonus to this is that random access iterators have an operator[] (like pointers) so you can do
vector<int>::iterator A::value_begin() {return values_.begin();}
vector<int>::const_iterator A::value_begin()const{return values_.begin();}
...
a.value_begin()[252]=3;
int b=a.value_begin()[4];
vector<int> c(a.value_begin(),a.value_end())
(although it maybe ugly enough that you'd still want your getters/setters in addition to this)
REGARDING INPUT VALIDATION:
In your example, the assignment happens in the calling code. If you want to validate user input, you need to pass the value to be validated into your struct object. This means you need to use member functions (methods). For example,
struct A {
// getter
int& getValue() const { return value_; }
// setter
void setValue(const int& value) {
// validate value here
value_ = value;
}
private:
int value_;
};
By the way, .NET properties are implemented are methods under the hood.
I have a thread-class Buffer (own made class), and many derived classes such as BufferTypeA, BufferTypeB...
Since I have to synchronize them in a certain order, I'm giving any of them an integer which represents the order to run certain task. I also have to know inside each thread Buffer which one is next to run the task, so I'm passing every BufferType a reference to an integer which all of them must share and I didn't want to make it Global.
I got lost at any point and I don't see where.
First I create all the BufferTypes from a class where I also define that shared integer as:
int currentThreadOrder;
And when creating the BufferTypes:
int position = 0;
if (NULL == bufferA) {
bufferA = new BufferTypeA(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferB) {
bufferB = new BufferPos(¤tThreadOrder, ++position,
waitCondition);
}
if (NULL == bufferC) {
bufferC = new BufferRtk(¤tThreadOrder, ++position,
waitCondition);
}
Then, in BufferTypeA header:
class BufferTypeA: public Buffer {
public:
BufferTypeA(int currentThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//..
}
And in cpp file:
BufferTypeA::BufferTypeA(int currentThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition):
Buffer(currentThreadOrder, threadConnectionOrder, waitCondition) { }
Now I'll show Buffer header:
class Buffer: public QThread {
public:
Buffer(int ¤tThreadOrder,
int threadConnectionOrder = 0,
QWaitCondition *waitCondition = NULL);
//...
protected:
QWaitCondition *waitCondition;
int threadConnectionOrder;
int ¤tThreadOrder; // Shared address
}
And finally the cpp:
Buffer::Buffer(int ¤tThreadOrder, int threadConnectionOrder, QWaitCondition *waitCondition) {
this->threadConnectionOrder = threadConnectionOrder;
this->waitCondition = waitCondition;
this->currentThreadOrder = currentThreadOrder;
}
And the error I'm getting is error: uninitialized reference member Buffer::currentThreadOrder.
I'm embarrased to ask, because it's going to be a simple problem with pointers and addresses, but I can't see where the problem is, so please help.
When you create a class with a data-member that is a reference, the reference needs to be assigned a value in the constructor initializer list.
References have to be given a value when they are created, they are not pointers. They have to start with a value and that value cannot be changed (while the contents that is pointed to by that value can be changed).
Essentially you can think of a reference as an alias for an existing variable. You can't give a friend a nickname if you don't have a friend :)
RESPONSE TO COMMENT:
You don't "share a reference" between objects. Each object will have its own reference to the same variable. When you "pass by reference" you are telling the compiler that you want the variable in your function to actually be the variable in your outer scope, rather than creating a new variable by value. This means that you only have one variable at one memory location. The reference is just memory in some other place that forwards you to that same memory location.
Think of this as call forwarding... I can have 15 phone numbers in 15 different countries. I can set them all up to forward calls to my cell in the US. So, people are calling me no matter which number they call.
Each of your classes just has another reference to forward the "phone calls" or variable reads/writes to that same memory location. So, you're not sharing a reference between classes, you're making sure that each class HAS a reference to the same underlying memory location.
Back to the metaphore, each class won't have the same phone, but each class' phone will forward to the same number (variable) none-the-less which lets them all set/get the same value in the end.
RESPONSE II:
Here's a simple example to get your head going, it's pretty easy to apply to your classes. I didn't compile it but it should work minus a typo or two possibly.
class A
{
public:
A(int& shared) : m_shared(shared)
{
//No actions needed, initializer list initializes
//reference above. We'll just increment the variable
//so you can see it's shared in main.
m_shared += 7;
}
void DoSomethingWithIt()
{
//Will always reflect value in main no matter which object
//we are talking about.
std::cout << m_shared << std::endl;
}
private:
//Reference variable, must be initialized in
//initializer list of constructor or you'll get the same
//compiler error again.
int& m_shared;
};
int main()
{
int my_shared_integer = 0;
//Create two A instances that share my_shared_integer.
//Both A's will initialize their internal reference to
//my_shared_integer as they will take it into their
//constructors "by reference" (see & in constructor
//signature) and save it in their initializer list.
A myFirstA(my_shared_integer);
A mySecondA(my_shared_integer);
//Prints 14 as both A's incremented it by 7 in constructors.
std::cout << my_shared_integer << std::endl;
}
you pass a pointer int* as 1st argument to BufferTypeA, which expects and int, while you said in your question you meant to use a int&. To do this, the ctor of BufferTypeA should take a int& and initialise it in an initialisation list (i.e. not within the { } part of the ctor) like
class BufferType {
int &Ref;
public:
BufferTypeA(int& ref) : Ref(ref) { /* ... */ }
};
and in your construction of BufferA you must not pass an address, but the reference, i.e.
int counter;
Buffer = new BufferType(counter);
You want code like this:
Buffer::Buffer(
int ¤tThreadOrder0,
const int threadConnectionOrder0,
QWaitCondition *const waitCondition0
) :
threadConnectionOrder(threadConnectionOrder0),
waitCondition(waitCondition0),
currentThreadOrder(currentThreadOrder0)
{}
The reason is related to the reason you cannot write
const double pi;
pi = 3.14;
but can write
const double pi = 3.14;
A reference is typically implemented as a constant pointer, to which one cannot assign an address after one has initialized the pointer. Your version of the code assigns, as in the first pi example. My version of the code initializes, as in the second pi example.