I'm having the problem where once I change a variable it seems to be unchanged when referenced later
in the code.
class foo
{
private:
string name;
public:
foo(string _name)
:name(_name)
{}
void info()
{ cout<<name; }
void newName(string new_name)
{ name = new_name; }
};
class bar
{
private:
string _name;
vector<foo> _content;
public:
foo at(int i)
{ return _content.at(i); }
void push_back(foo newFoo)
{ _content.push_back(newFoo); }
};
int main()
{
foo test("test");
bar kick;
kick.push_back(test);
kick.at(0).newName("nice");
kick.at(0).info();
return 0;
}
I would like the program to return "nice" but it returns "test".
I imagine this has something to with scope but I do not know.
How would I write something that can get around this problem?
This member function
foo at(int i)
{ return _content.at(i); }
returns a copy of the object stored in the vector.
If you want to get the expected result then return reference.
foo & at(int i)
{ return _content.at(i); }
const foo & at(int i) const
{ return _content.at(i); }
Related
Two classes: Data is parent and DerivedData is child. Why does cout output "Data"?
class Data {
protected:
int _value {};
public:
Data(int value) : _value{ value } { }
std::string getName() const {
return "Data";
}
int getValue() const {
return _value;
}
void setValue(const int i) {
_value = i;
}
};
class DerivedData: public Data {
public:
DerivedData(int value) : Data{ value } { }
std::string getName() const {
return "DerivedData";
}
int getValueDoubled() const {
return _value * 2;
}
};
DerivedData dd{ 5 };
Data d = dd;
Data& rd = dd;
cout << rd.getName() << endl;
This code will output "Data", but why?
You are not using virtual so it is kinda redefinition of the parent function which you think is polymorphsim but it is not.
When it execute this line of code Data& rd = dd; you had expected to be printed DerviedData but this did not happen because your function was not virtual, and base class do not know you are overriding the getName method in derived class.
So to fix this issue need to declare your function virtual:
virtual std::string getName() const { return "Data"; } //Data
And in DerivedData:
std::string getName() const override { return "DerivedData"; } //DerivedData
Now this will behave the way you'd expected.
What is the correct syntax to do this? Surely I made some stupid mistake ... unfortunately I'm trying to better understand the vectors. I know that I created an unnecessary pointer, but I need to understand the syntax.
#include <iostream>
#include <vector>
class otherClass
{
public:
otherClass(int x):value(x)
{
//ctor
}
int getValue()
{
return value;
}
private:
int value;
};
class MyClass
{
public:
MyClass(int x)
{
obj = new std::vector<otherClass>(x,otherClass{5});
}
otherClass getVector()
{
return obj; //HERE FIRST ERROR <---------------
}
private:
std::vector<otherClass>*obj;
};
void doSomething(otherClass*obj)
{
std::cout << obj->getValue() << std::endl;
}
int main()
{
MyClass*aClass = new MyClass(10);
doSomething(aClass->getVector()); //HERE SECOND ERROR <---------------
return 0;
}
Errors that I get when compiling:
First:
error: invalid conversion from 'std::vector<otherClass>*' to 'int' [-fpermissive]
Second:
error: cannot convert 'otherClass' to 'otherClass*' for argument '1' to 'void doSomething(otherClass*)'
First of all, there is no point in using any pointer here. None!
Second, your getters should be qualified const, and return const references for heavy objects like your vector. It prevents an useless copy.
int getValue() const
// ^^^^^
{
return value;
}
within otherClass, and
class MyClass
{
public:
MyClass(int x) : obj(x, otherClass{5}) // construction here
{ }
std::vector<otherClass> const & getVector() const
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^
{
return obj;
}
private:
std::vector<otherClass> obj; // no pointer, just a vector
};
Then in the main:
MyClass aClass(10);
What you want to do with doSomething() is unclear. With your code doSomething(aClass->getVector()) you're supposed to handle the returned vector of otherClasses. So it should be:
void doSomething(std::vector<otherClass> const & obj)
I let you write its code.
just say what you want to return
std::vector<otherClass> *getVector()
{
return obj;
}
or
std::vector<otherClass> getVector()
{
return *obj;
}
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
is there any generic way to take an existing class, and "constify" it by removing all non-const functionality?
One possible workaround is to create a wrapper class that holds an instance of the class and only gives access to a const reference to it.
template<class T>
class Immutable {
public:
template<typename... Args>
Immutable(Args&&... args) : instance(forward<Args>(args)...) {
}
operator const T&() {
return instance;
}
const T& get() const {
return instance;
}
private:
Immutable& operator=(const Immutable& other) = delete;
T instance;
};
Suppose you have a mutable class Class:
class Class {
public:
Class() : m_value(0) {
}
Class(const Class& other) : m_value(other.m_value) {
}
Class(int value) : m_value(value) {
}
Class(int x, int y) : m_value(x + y) {
}
void change(int value) {
m_value = value;
}
int value() const {
return m_value;
}
private:
int m_value;
};
Here is how Immutable<Class> can be used:
void functionTakingConstReference(const Class& x) {
}
void functionTakingNonConstReference(Class& x) {
}
void functionTakingImmutableClass(Immutable<Class>& x) {
}
void functionTakingValue(Class x) {
}
int main(int argc, char *argv[])
{
// Any constructor of Class can also be used with Immutable<Class>.
Immutable<Class> a;
Immutable<Class> b(1);
Immutable<Class> c(2, 3);
Immutable<Class> d(c);
// Compiles and works as expected.
functionTakingConstReference(a);
functionTakingImmutableClass(a);
functionTakingValue(a);
cout << a.get().value() << endl;
// Doesn't compile because operator= is deleted.
// b = a;
// Doesn't compile because "change" is a non-const method.
// a.get().change(4);
// Doesn't compile because the function takes a non-const reference to Class as an argument.
// functionTakingNonConstReference(a);
return 0;
}
Is there any way to force to only allow const instances of class to be instantiated, and have non-const instances be detected as an error by the compiler?
No.
But you can declare all members as const. Then both const and non-const instances would behave largely in the same way and it shouldn't matter whether the instances are const.
I think you are looking for an immutable class. An easy way to get immutability is to declare all member variables as const. This way you ensure that the state of your objects will not change after construction.
This guarantee is independent of whether your object is const and even if you have non-const member functions for that class.
For example:
class Foo
{
public:
Foo(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
private:
const int m_id;
const double m_value;
};
Another way you could generate an immutable object of any type is through a template class. Something like this:
class Bar
{
public:
Bar(int id, double value) : m_id(id), m_value(value) { }
int Id() const { return m_id; }
double Value() const { return m_value; }
void SetId(int id) { m_id = id; }
private:
int m_id;
double m_value;
};
template<typename T>
class MyImmutable
{
public:
const T m_obj;
MyImmutable(const T& obj) : m_obj(obj)
{ }
};
int main()
{
cout << "Hello World!" << endl;
Foo a(1,2.0);
Bar x(2,3.0);
MyImmutable<Bar> y(x);
cout << "a.id = " << a.Id() << endl;
cout << "a.value = " << a.Value() << endl;
cout << "y.id = " << y.m_obj.Id() << endl;
cout << "y.value = " << y.m_obj.Value() << endl;
y.m_obj.SetId(2); // calling non-const member throws an error.
return 0;
}
I have a simple class which consists of a void pointer and an int (this is some sort of a boost::Variant educational project).
I also have a working copy constructor and a destructor.
But what grinds my gears is, how I would accomplish something like this:
Container cont1("some value"); //simple construction
Container cont2;
cont2.createLink(cont1); //this should initialize members with a reference (or something alike)
std::cout<<cont1; //yields "some value"
cont2.set(20); //setting this container should update the original container too, since I initialized with a reference (or smth alike)
std::cout<<cont1; //yields 20
This is the simplified version of the class:
class Container {
public:
Container(){}
Container(const std::string &val){var.type = STRING; var.data = new std::string(val);}
Container(int val){ /* same for int */}
Container(const Container &val){ /* do a memory copy */}
void set(int val){ /* set the value if type matches, otherwise allocate a new pointer */}
void set(const std::string &val){ /* the same as for int */}
void createLink(const Container &val){ /* somehow assign a reference or whatsoever */}
private:
typedef struct VAR {
int type = 0;
void *data = NULL; }
VAR var;
}
If I set the value of cont2 to a string (i.e. the same data type it holds at the moment), everything is fine, because the set would not allocate a new pointer and rather assign a new value.
But how do I make sure the pointer of cont1 updates if I assign a different value to cont2 and therefore have to allocate a new pointer?
Would I need something like shared_pointer?
Thanks for any insight!
EDIT:
I changed to function name to make it more clear what should happen.
There is a solution that only involves straight OO. You could create an interface for your variant type, and use double indirection to the variant instance to allow linked containers to share the same variant instance.
The reason double indirection is required is because of the way you want the set() method to automatically allocate a new variant instance if the new type doesn't match the original type. If we simply shared a pointer to the variant from both containers, then after set() creates a new variant instance, each container would be referring to different instances again.
To get around that, we can use a pointer to a pointer to a variant in the container instead.
Here is a possible way to define your variant interface, and how it could be subclassed:
typedef std::ostream Out;
struct BadType {};
struct Var {
virtual ~Var () = default;
virtual Out & print (Out &os) { return os << "(BadType)"; }
virtual void set (int) { throw BadType(); }
virtual void set (const std::string &) { throw BadType(); }
};
struct VarInteger : Var {
int data;
VarInteger (int v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (int v) throw() { data = v; }
};
struct VarString : Var {
std::string data;
VarString (const std::string &v) : data(v) {}
Out & print (Out &os) { return os << data; }
void set (const std::string &v) throw() { data = v; }
};
Here is how you could define your pointer to pointer, and how they could be initialized:
typedef std::shared_ptr<Var> VarPtr;
std::shared_ptr<VarPtr> varptr_;
static VarPtr make_var () { return std::make_shared<Var>(); }
static VarPtr make_var (int v) { return std::make_shared<VarInteger>(v); }
static VarPtr make_var (const std::string &v) {
return std::make_shared<VarString>(v);
}
VarPtr & var () { return *varptr_; }
const VarPtr & var () const { return *varptr_; }
Container () : varptr_(std::make_shared<VarPtr>(make_var())) {}
Container (int v) : varptr_(std::make_shared<VarPtr>(make_var(v))) {}
Container (const std::string &v)
: varptr_(std::make_shared<VarPtr>(make_var(v))) {}
And here is how your set() methods and createLink() method could be implemented.
void set (int v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void set (const std::string &v) {
try { var()->set(v); }
catch (BadType) { var() = make_var(v); }
}
void createLink (const Container &val) { varptr_ = val.varptr_; }
Demo
How about the following. Of course createLink cannot not take a const reference so I made it to take a non-const pointer.
class Container {
const int STRING = 0x0000001;
const int INT = 0x0000002;
const int LINK = 0x8000000;
public:
...
void set(int val){...}
void set(const std::string &val)
{
if (var.type == LINK)
{
reinterpret_cast<Container*>(var.data)->set(val);
}
else
...
}
void createLink(Container* val)
{
var.data = val;
var.type = LINK;
}
private:
typedef struct VAR {
int type = 0;
void *data = NULL;
};
VAR var;
};
There are a some important points to think about - relative lifetimes of the link and the linked is the most obvious one.
Why can't I use the function ColPeekHeight() as an l-value?
class View
{
public:
int ColPeekHeight(){ return _colPeekFaceUpHeight; }
void ColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
if( v.ColPeekHeight() > 0.04*_heightTable )
v.ColPeekHeight()-=peek;
}
The compiler complains at v.ColPeekHeight()-=peek. How can I make ColPeekHeight() an l-value?
Return the member variable by reference:
int& ColPeekHeight(){ return _colPeekFaceUpHeight; }
To make your class a good one, define a const version of the function:
const int& ColPeekHeight() const { return _colPeekFaceUpHeight; }
when I declare the function with the
two consts
When you want to pass an object into a function that you don't expect it to modify your object. Take this example:
struct myclass
{
int x;
int& return_x() { return x; }
const int& return_x() const { return x; }
};
void fun(const myclass& obj);
int main()
{
myclass o;
o.return_x() = 5;
fun(o);
}
void fun(const myclass& obj)
{
obj.return_x() = 5; // compile-error, a const object can't be modified
std::cout << obj.return_x(); // OK, No one is trying to modify obj
}
If you pass your objects to functions, then you might not want to change them actually all the time. So, to guard your self against this kind of change, you declare const version of your member functions. It doesn't have to be that every member function has two versions! It depends on the function it self, is it modifying function by nature :)
The first const says that the returned value is constant. The second const says that the member function return_x doesn't change the object(read only).
It can be rewritten like:
class View
{
public:
int GetColPeekHeight() const { return _colPeekFaceUpHeight; }
void SetColPeekHeight( int i ) { _colPeekFaceUpHeight = i; }
private:
int _colPeekFaceUpHeight;
};
...
{
cph = v.GetColPeekHeight();
if ( cph > 0.04 * _heightTable )
v.SetColPeekHeight( cph - peek );
}