For certain reasons, I want to have multiple instances of class A all have access to a single instance of class B. B has public member functions that allow objects of A to get data from B, but not to change it. I'm trying to do this by declaring an object of B in my main function, then passing it to the constructor when I declare objects of type A.
void main () {
B obj_b;
A A1(obj_b);
A A2(obj_b);
A A3(obj_b);
cout << A1.getfoo() << endl;
cout << A2.getfoo() << endl;
count << A3.getfoo() << endl;
}
class B{
private:
int foo = 9;
public:
int getfoo(){return foo;}
};
class A {
private:
B *bptr;
public:
A(B b){ this->bptr = &b; }
int getfoo(){ return bptr->getfoo(); }
};
This compiles and runs, but I get very weird results. The return values from getfoo are sometimes correct sometimes incorrect. Am I handling the pointers incorrectly? Is there a better way to do this?
In the A constructor, the argument b is a local variable, its life-time ends when the constructor function ends. You can't save a pointer to it, that pointer will become invalid immediately.
Either use smart pointers, or use a reference and constructor initializer lists:
class A
{
public:
// Pass by reference
A(B& b)
: b{ b } // Initialize the member variable b with the argument b
{
// Empty body
}
private:
B& b; // Reference to a B object
};
Related
I've got weird thing which, by my experience, I can call bug in C++. When I call this program:
#include <iostream>
using namespace std;
class foo {
public:
int a;
foo(int a = 0) : a(a) {}
} a1;
class bar {
foo a;
public:
bar(foo a = a1) : a(a) {
a.a = 1;
cout << a.a << endl;
}
void print_a() {
cout << a.a << endl;
}
};
int main() {
bar zz;
zz.print_a();
a1.a = 2;
bar zz1;
zz1.print_a();
}
The output is:
1
0
1
2
I do expect to be able to change values of internal members of my class, like the a value of the object of foo class inside bar class. When I change the a.a value in bar constructor, it looks like I changed only local variable. What is the mechanism of this process? C++ does not treat variables inside its class as constant parameters, because I can as well get counter which is changed by methods. But when counter is one class more deeper, the structure seems to collapse.
Within the constructor body, argument names hide member names, so as you surmised, you're modifying the function argument a, not the member a.
You can refer to the member as this->a or bar::a to disambiguate, if you don't want to rename either variable.
First, I'm Java coder and want to understand polymorphism in c++. I wrote the example for learning purposes:
#include<iostream>
using namespace std;
class A
{
public:
virtual void foo(){ std::cout << "foo" << std::endl; }
};
class B : public A
{
public:
void foo(){ std::cout << "overriden foo" << std::endl; }
};
A c = B();
int main(){ c.foo(); } //prints foo, not overriden foo
I expected that overriden foo would be printed, but it wasn't. Why? We overrode the method foo in the class B and I thought that the decision which method should be called is being making from the runtime type of the object which in my case is B, but not a static type (A in my case).
Live example is there
When you do this:
A c = B();
You're converting the B value into A. You don't want that.
You should make a B object and access it through an A pointer or reference to get polymorphic behaviour:
B b;
A& c = b;
In java, you have value semantics with types like int and float, and you have reference semantics with everything else.
That's not the case in C++: the type system is unified, and you get whichever of value or reference semantics that you ask for.
With the code you've written
A c = B()
you've told the compiler to create a new value of type B, and then convert it to a value of type A, storing the value in c. Conversion, in this case, means taking A data out of the new B instance you created it, and copying it into the new A instance stored in c.
You could do this instead:
B b;
A &c = b;
This still creates the value b, but now c is a reference to A, which means c will now refer to the B instance you created, rather than being a copy of its A part.
Now, this still creates b as a local variable, and the object stored in b gets destroyed as soon as b goes out of scope. If you wanted something more persistent, you'd need to use pointers; e.g. something like
shared_ptr<A> c = make_shared<B>();
c->foo();
You could do something more 'raw' like
A *b = new B();
but this is a 'dumb' pointer; shared_ptr is smarter and your object will get destroyed when nothing else references it. If you do the latter, you'd have to do the destruction yourself when appropriate (and messing this up is a common source of mistakes)
Your confusion stems from a crucial difference between Java and C++.
In Java if you write
MyClass var = whatever;
your variable var is a reference to the object returned by whatever. However, in C++ this syntax means "create a new object of type MyClass by passing the result of the expression whatever to an appropriate constructor, and copy the resulting object into the variable var.
In particular, your code creates a new object of type A, named c, and passes a temporary default-constructed object of type B to its copy constructor (because that's the only constructor that fits). Since the newly created object is of type A, not of type B, obviously A's method foo is called.
If you want to have a reference to an object, you have to explicitly request that in C++, by adding & to the type. However a reference to non-constant objects cannot be bound to temporaries. therefore you need to explicitly declare also the object you bind to (or alternatively, use a reference to a const object, and fix your foo member functions to be const, since they don't change the object anyway). So the simplest version of your code doing what you want would read:
// your original definitions of A and B assumed here
B b; // The object of type B
A& c = b; // c is now a *reference* to b
int main() { c.foo(); } // calls B::foo() thanks to polymorphism
However the better version would be const-correct, and then could use your original construction:
#include <iostream>
class A
{
public:
virtual void foo() const // note the additional const here!
{ std::cout << "foo" << std::endl; }
};
class B : public A
{
public:
void foo() const // and also const here
{ std::cout << "overridden foo" << std::endl; }
};
A const& c = B(); // Since we bind to a const reference,
// the lifetime of the temporary is extended to the
// lifetime of the reference
int main() { c.foo(); } //prints overridden foo
(note that I removed using namespace std; because it's a bad thing to do (and your code used explicit std:: anyway, so it's just redundant).
Note however, that C++ references are still different from Java references in that they cannot be reassigned; any assignment goes to the underlying object instead. For example:
#include <iostream>
class A { public: virtual void foo() const { std::cout << "I'm an A\n"; } };
class B: public A { public: void foo() const { std::cout << "I'm a B\n"; } };
class C: public A { public: void foo() const { std::cout << "I'm a C\n"; } };
B b;
C c;
int main()
{
A& ref = b; // bind reference ref to object b
ref.foo(); // outputs "I'm a B"
ref = c; // does *not* re-bind the reference to c, but calls A::operator= (which in this case is a no-op)
ref.foo(); // again outputs "I'm a B"
}
If you want to change the object you refer to, you'll have to use pointers:
// definitions of A, B and C as above
int main()
{
A* prt = &b; // pointer ptr points to b
prt->foo(); // outputs "I'm a B"
prt = &c; // reassign ptr to point to c
prt->foo(); // outputs "I'm a C"
}
The line of interest is this (using uniform initialization syntax instead):
A c = B{};
It is important to note that, when declared this way, c behaves like a value.
Your code constructs a local A named c out of an instance of B. This is called slicing: Any part of that B that isn't also part of an A has been "sliced" away, leaving only an A.
Giving a symbol reference semantics in C++ (called indirection) requires a different notation.
For example:
A &c = B{};
A d = B{}; // Casts the intermediate B instance to const A &,
// then copy-constructs an A
c.foo(); // calls B::foo because c points to a B through an A interface
d.foo(); // calls A::foo because d is only an instance of an A
Note that the lifetime of the intermediate B to which c points is automatically extended to the scope of c. On the other hand, the second intermediate B is destroyed after the construction of d has completed.
In C++, references are immutable (they cannot be changed after initialization). When used in an expression, it is as though the object (value) to which they are pointing were used instead:
A &c = B{};
c = A{}; // Calls the compiler-provided A::operator = (const A &)
// (a virtual assignment operator with this signature
// was not defined).
// This DOES NOT change where c points.
Pointers, on the other hand, can be changed:
A a{};
B b{};
A *cptr = &b;
cptr->foo(); // calls B::foo
cptr = &a;
cptr->foo(); // calls A::foo
exactly what orlp said. you should also learn to use pointers too (they are fun)
A* c = new B();
c->foo(); // overriden foo
delete c;
This is the code I have. Base class has member variable i and derived class also has same member variable name. Now client creates Base ptr pointing to derived and accesses member variable directly using i. I thought it would call derived member variable, instead it calls base class variable. I am not sure why this is?
#include<iostream>
using namespace std;
class A{
public:
int i;
A(int ii=5):i(ii){}
virtual void display(){
cout<<" In A :"<<i<<endl;
}
};
class B: public A{
public:
int i;
B(int ii=7):i(ii){}
void display(){
cout<<" In B :"<<i<<endl;
}
};
int main(){
A * aptr = new B();
cout << aptr->i <<endl; // expected B::i but gave A::i
aptr->display();
B bb;
bb.display();
return 0;
}
Is there a good reason for this. I thought like vptr is member variable of object(when new B was called) and this vptr calls correctly when we type aptr->display. Why isn't the same thing happening with i.
Member variables in C++ are not shadowed by inheritance the way virtual functions are.
If B inherits from A, and they both define a member named i, both of those variables exist and are independently part of the object.
Since your pointer has the type A*, the expression aptr->i will resolve to A's version of i.
As a side note, B can also explicitly access A's version of i, as long as it is not private.
class B: public A{
public:
int i;
B(int ii=7):i(ii){}
void display(){
cout<<" In B :"<<i<<endl;
cout<<" In A :"<<A::i<<endl;
}
};
This is what I wanted to ask and luckily was able to write in main func the stuff i needed.
Please check and let me know why A& and A instance behave differntly.
int main(){
A * aptr = new B();
cout << aptr->i <<endl;
aptr->display();
B *bptr = dynamic_cast<B*>(aptr);
bptr->display();
cout << bptr->i <<"\t" <<bptr->A::i<<endl;
A & aref = static_cast<A&>(*aptr);
cout <<endl <<"Called ref : "<<aref.i<<endl;
aref.display(); // here it calls B::display
A aa(*aptr);
cout <<endl <<"Called Inst : "<<aa.i<<endl;
aa.display(); // here it calls A::display
delete aptr;
return 0;
}
Question is why aref and aa behave differently?
My understanding is when instance of B was created using new B(). there were 2 variables in it, "i" and vptr of class B.
When aref is created, it called vptr of B for display,
but aa calls A::display,
While for both cases slicing is happening then how does it behave differently.
I am asking question in terms of memory is allocated to any class instance and when ptr of base is pointing to derived class. Hope you understand my confusion.
So say I have 3 classes: Base, A, and B.
Base is a base class for both class A and class B.
Base has a variable val that A and B can access.
How would I get it to work where I can set the val variable through class A, and it is reflected in class B?
For example:
I know this code below won't work because I am creating an OBJECT of the type a and b.
What I want to do is to simply have a and b share the same variable so that whenever a does something to it, it is reflected in b.
a aa;
b bb;
aa.SetVal(50000);
cout << aa.GetVal() << endl;
cout << bb.GetVal() << endl;
In the end I'd want both cout lines to print out 50000.
EDIT: The classes A and B will be doing different operations and just need to be able to access/change the val variable in base
You could make the member a static member of the base class, then all derived classes could access it, however any object of a derived that changes the static member would change it for every other object.
class Base
{
public:
int GetVal()
{
return val;
}
void SetVal( int newVal )
{
val = newVal;
}
private:
static int val;
};
// Need to instantiate the static variable somewhere
int Base::val = 0;
class A : public Base
{};
class B : public Base
{};
class Base {
static int value;
public:
virtual ~Base() { }
void setVal(const int& val) {
value = val;
}
int getVal() const {
return value;
}
};
int Base::value = 0;
class A : public Base {
};
class B : public Base {
};
#include <iostream>
int main() {
A a;
B b;
a.setVal(20);
std::cout << b.getVal(); // 20
}
That's a job for references, not for classes. Just have one class X and create a reference to the object:
X aa;
X& bb = aa;
aa.SetVal(50000);
std::cout << aa.GetVal() << std::endl;
std::cout << bb.GetVal() << std::endl;
The output will be:
50000
50000
Remember to always use the right tool for the job and keep things simple.
The main goal is that those two classes will be doing different things but will need to be able to access and share a single variable.
An idea to solve this is to extract the common variable in another class, namely S, which will be passed to A and B like this:
std::shared_ptr<S> s = new S();
A aa(s);
B bb(s)
Now, both aa and bb share the same S object and can modify it very easily. Notice that the constructor of both A and B should store the std::shared_ptr<S> as well:
class A { // and B
private:
std::shared_ptr<S> s;
public:
A(std::shared_ptr<S> as) : s(as) {}
};
The variable s will last as long as any of aa and bb is alive: when both aa and bb gets deallocated or go out of scope, the variable s will be deallocated as well.
If the type of the common variable should be on the stack, you can also just use references, but watch out for the lifetime of aa, bb and that variable:
int s = 0;
A aa(s);
B bb(s);
with:
class A { // and B
private:
int& s; // or any other type
public:
A(int& as) : s(as) {}
};
But as a general rule of thumb I'd avoid shared state between objects. Most of the time, depending on the context, you can refactor your code and get rid of the shared dependency.
If the shared value is static in the base class, then all instances of derived classes will see exactly that one base class member.
If the value is not static, then each instance of a class will have its own copy whether or not the value is in a base class.
Not sure I understand what you are trying to do. Do you want all instances of A and B to share the same value? if so, declare it as static in the base class.
if not, how do you want to choose which one will share the value?
I have the code:
class A{ //base class
public:
virtual std::string getString(){return "class A";}
};
class B: public A{
public:
std::string getString() {return "it is B class";}
};
class C{
public:
C(){
B b;
a = b;
}
std::string test() {return a.getString();}
private:
A a;
};
int main()
{
C c;
std::cout << c.test();
return 0;
}
c.test() says "class A", but how I can call method getString() from class B and not A?
Thanks!
The problem is, your B object gets sliced when assigned to an A object. This is because you assigned by value, not by reference or pointer. Since you declared a like this
A a;
what happens during the assignment a = b is that the actual state of b is copied over into a. However, since a is a value object, only the A part of object b is copied, and its "B-ness" is completely lost!
To avoid this, you need to declare a as a pointer type, as suggested by others (a reference would also work, but then you would need to considerably rewrite your example, since you can't assign to references, only initialize them). If a is a pointer (A*), the assignment a = b makes a point to the object represented by b, which is still a B object, thus you will observe the polymorphic behaviour you expected. However, in this case, you must ensure that b stays alive even after exiting the constructor - otherwise you leave a dangling reference which causes undefined behaviour (read: bad things you don't want to happen) when dereferenced.
Since a pointer example was already shown by #Nawaz, I will give another using a reference:
class C{
public:
C() : a(b) { // references must be initialized in the constructor initializer list
}
std::string test() {return a.getString();}
private:
B b; // moved to class scope to ensure that it stays alive
A& a;
};
You need to implement like this:
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
This will call getString() from class B and not A.
What you're trying to do is called "dynamic polymorphism" which is achieved through pointer (or reference) of type base class (which is A), but the pointer points to an object of type derived class (which is B).
Because your member a is not an A*, it is an A instance. Therefore you are just assigning the A part of B to variable a. if you convert a to an A*, you will get the expected result.
You are slicing therefore it will not work. a is an A it is not a B.
To work your class member variable a must be a pointer or a reference.
As a pointer
class C{
public:
C(){
a = new B;
}
std::string test() {return a->getString();}
private:
A *a;
};
As a reference
class C{
public:
C() : a( *(new B) )
{
}
std::string test() {return a.getString();}
private:
A &a;
};
Of course the code I have produced leaks but will work with the virtual function.