I have a program with a lot of classes. I want classes in the program to be visible to each other. For that, I am following a trick such that all classes are inherited from a base class, which holds pointers to every class. But I hit an error in doing so. Below is a piece of code produces the error I am after:
#include <iostream>
using namespace std;
class AClass;
class BClass;
class RoofClass {
public:
RoofClass();
AClass* a_class;
BClass* b_class;
};
class BaseClass {
public:
BaseClass(RoofClass* roof_class) {
a_class = roof_class->a_class;
b_class = roof_class->b_class;
}
AClass* a_class;
BClass* b_class;
};
class AClass : public BaseClass {
public:
AClass(RoofClass* roof_class) : BaseClass(roof_class) {}
void Afunction();
int Aint = 1;
};
class BClass : public BaseClass {
public:
BClass(RoofClass* roof_class) : BaseClass(roof_class) {}
void Bfunction();
int Bint = 2;
};
void AClass::Afunction() {
cout << b_class->Bint << endl;
}
void BClass::Bfunction() {
cout << a_class->Aint << endl;
}
RoofClass::RoofClass() {
a_class = new AClass(this);
b_class = new BClass(this);
}
int main(int argc, char **argv) {
RoofClass roof_class;
cout << "b calls a" << endl;
roof_class.b_class->Bfunction();
cout << "a calls b" << endl;
roof_class.a_class->Afunction();
}
Roof is the top level class which consists of classes A and B. I want A and B visible to each other. To achieve that, as I said, they both inherit from the Base class. My problem, in particular, is that while B sees A, A does not see B. The reason for this is probably due to the fact that A is initialized before B in constructor of Roof. So, why can I solve this issue?
When RoofClass constructor creates an instance of AClass, it passes a pointer to itself, with uninitialized members a_class and b_class. AClass constructor then copies those values and returns. When RoofClass constructor sets a_class to point to the newly constructed object, the pointers inside AClass are still pointing to nothing.
You probably want BaseClass to store a pointer to RoofClass instead:
class BaseClass {
public:
BaseClass(RoofClass* roof_class) {
r_class = roof_class;
}
RoofClass* r_class;
};
class AClass : public BaseClass {
public:
AClass(RoofClass* roof_class) : BaseClass(roof_class) {}
void Afunction();
int Aint = 1;
// access class B as r_class->b_class
};
I actually solved the question. It is like this:
In its constructor, the RoofClass creates a and b objects, in order. It first initializes a object by going into its constructor (which actually is the constructor of BaseClass due to inheritance) and setting a's a and b objects to roof's a and b. But the problem is that, roof's b is not constructed yet. That is why, a's b is initialized to a value of 00000000. When the RoofClass goes to b object's constructor for initialization, this time both roof's a and b are in place so that b's a and b's b are properly initialized. That is why, b can have a proper a but not vice versa.
The solution is introducing an InitPointer function to the base class, which acts after the roof objects constructs all a and b objects. This way, InitPointer sets pointers of a and b objects to already constructed a and b objects. Here is the working code:
#include <iostream>
using namespace std;
class AClass;
class BClass;
class RoofClass {
public:
RoofClass();
AClass* a_class;
BClass* b_class;
};
class BaseClass {
public:
BaseClass() {}
void InitPointer(RoofClass* roof_class) {
a_class = roof_class->a_class;
b_class = roof_class->b_class;
}
AClass* a_class;
BClass* b_class;
};
class AClass : public BaseClass {
public:
AClass() : BaseClass() {}
void Afunction();
int Aint = 1;
};
class BClass : public BaseClass {
public:
BClass() : BaseClass() {}
void Bfunction();
int Bint = 2;
};
void AClass::Afunction() {
cout << b_class->Bint << endl;
}
void BClass::Bfunction() {
cout << a_class->Aint << endl;
}
RoofClass::RoofClass() {
a_class = new AClass();
b_class = new BClass();
a_class->InitPointer(this);
b_class->InitPointer(this);
}
int main(int argc, char **argv) {
RoofClass roof_class;
cout << "b calls a" << endl;
roof_class.b_class->Bfunction();
cout << "a calls b" << endl;
roof_class.a_class->Afunction();
}
Thanks for the all discussion!
Related
Here is what UML looks like CLASS UML
ClassA has an pointer to ClassB, and ClassB has a pointer to ClassC. I was wondering if I can access functions of ClassA in ClassC without inheriting ClassA.
Q: I was wondering if I can access functions of ClassA in ClassC without inheriting ClassA.
A: Yes, it is possible to access functions of ClassA in ClassC. Either by calling static member functions of classA or by providing specific instance of classA to ClassC. It may look like that classA can be accesed by following the pointers in reverse direction (ClassC to ClassB to ClassA) but that is not possible. Pointers point to values only in one direction.
This is interesting question about differences between a class and instances of class (objects). The following example shows why there is no classA::callAnyMethod():
#include <iostream>
class B;
class C;
class A
{
public:
A(B *next, int value) : next_(next), value_(value) { }
void af1() const { std::cout << value_ << "\n"; }
static void af2() { std::cout << staticValue << "\n"; }
protected:
B *next_;
int value_;
static int staticValue;
};
int A::staticValue = 3;
class B
{
public:
B(C *next) : next_(next) { }
protected:
C *next_;
};
class C
{
public:
void cf1(const A &a) { a.af1(); }
void cf2() { A::af2(); }
};
int main()
{
C c;
B b(&c);
A a1(&b, 1);
A a2(&b, 2);
// a1 is first instance of class A.
// One 'A::value_' is defined in a1 and is equal to 1.
c.cf1(a1);
// a2 is second instance of class A.
// Second 'A::value_' is defined in a2 and is equal to 2.
c.cf1(a2);
// Without specific instance of class A, we can use only static member
// 'A::staticValue' which is defined at file scope and is equal to 3.
// 'A::staticValue' is not part of objects (instances) of class A.
c.cf2();
return 0;
}
I try to do something like this:
class A{
public:
A(){number = 1;}
int number;
};
class B : public A{
public:
B(){number = 2;}
};
class Base {
public:
Base() {myAttribute = new A();}
int returnAttrNumber(){return myAttribute->number;}
A *myAttribute;
};
class Inherited : public Base{
public:
Inherited(){myAttribute = new B();}
B *myAttribute;
};
int main()
{
Inherited *i = new Inherited();
std::cout << i->returnAttrNumber(); // outputs 1, because it gets the A not the B. I want it to output 2, to get the B object in returnAttrNumber()
}
So, class Base holds an object A. Inherited holds an A-derived object B. And I try to call a method on the base class, but I want it to cast down in the hirarchy of the corresponding Object as far as possible (without static_cast or dynamic_cast) and then take the B object, not A and do stuff (returning it's number in in this case)
Is there a way to do that downcasting from a base class in C++ without big difficulties?
Thanks for answers!
This is very bad design. The quick answer is you can access variable from the base class via the fully qualified identifier. Take the following example:
#include <iostream>
class A
{
public:
A()
: var(1) {}
protected:
int var;
};
class B : public A
{
public:
B()
: var(2) {}
int getBVar() const
{
return var;
}
int getAVar() const
{
return A::var;
}
private:
int var;
};
int main()
{
B b;
std::cout << "A: " << b.getAVar() << std::endl;
std::cout << "B: " << b.getBVar() << std::endl;
}
Which outputs the following:
A: 1
B: 2
About the down casting bit... Base and Inherited have different variables. You can not safely case one to the other.
Well as rioki said,
Base and Inherited have different variables
This is because I redeclared MyAttribute as a B in Inherited. This was the mistake. I thought, when I declare it with the same name, it will be the same variable, that's wrong.
So the whole solution for this is to uncomment this one line in Inherited. Working code:
class A{
public:
A(){number = 1;}
int number;
};
class B : public A{
public:
B(){number = 2;}
};
class Base {
public:
Base() {myAttribute = new A();}
int returnAttrNumber(){return myAttribute->number;}
A *myAttribute;
};
class Inherited : public Base{
public:
Inherited(){myAttribute = new B();}
//B *myAttribute;
};
int main()
{
Base *i = new Inherited(); // this works, what is necessary in my case
std::cout << i->returnAttrNumber(); // outputs 2 now
}
For instance, I have base class A:
class A {
public:
callA() {
val = 100;
std::cout << this->val << std::endl;
}
int val;
}
class B : public A {
public:
B() {
val = 10;
}
int val;
}
B b;
b.callA();
What will b.callA() print?
And for B inheriting A, if B does not have a field val, will B share an exact reference to A's val, or is it a copy?
Internally, any instance of Class B contains an entire copy of Class A. In fact, when you initialize a new instance of Class B, Class A's constructor is run first. Therefore, when you call a non-virtual function from the base class, it will run as if it were run from the base class, which is internal to the derived class. It can even access the private variables of the base class (which the derived class wouldn't be able to access, it only has access to public/protected variables from the base class).
Example:
#include <iostream>
using namespace std;
class A
{
public:
A()
{
cout << "Base constructor!" << endl;
privateVar = 10;
}
void testPrint()
{
cout << "privateVar: " << privateVar << endl;
}
private:
int privateVar;
};
class B : public A
{
public:
B()
{
cout << "Derived Constructor!" << endl;
}
};
int main()
{
B testB;
testB.testPrint();
return 0;
}
I have a class structure similar to the following
class A
{
public:
A(void);
~A(void);
void DoSomething(int i)
{
std::cout << "Hello A" << i << std::endl;
}
};
class B : public A
{
public:
B(void);
~B(void);
void DoSomething(int i)
{
std::cout << "Hello B" << i << std::endl;
}
};
class Ad : public A
{
public:
Ad(void);
~Ad(void);
};
class Bd : public B
{
public:
Bd(void);
~Bd(void);
};
I want to store instances of the derived classes in a container (standard map) as a collection of A*, then iterate through the container and call methods for each instance.
#include "A.h"
#include "B.h"
#include "Ad.h"
#include "Bd.h"
#include <map>
int main(int argc, char** argv)
{
std::map<int,A*> objectmap;
objectmap[1] = new Ad();
objectmap[2] = new Bd();
for (std::map<int,A*>::iterator itrobject = objectmap.begin();
itrobject!=objectmap.end(); itrobject++)
{
itrobject->second->DoSomething(1);
}
return 0;
}
The above code produces the following output.
Hello A1
Hello A1
Where I was expecting
Hello A1
Hello B1
because I was expecting DoSomething in B to hide DoSomething in A, and because I am storing A pointers, I would expect no object slicing (and looking at the object pointer in the debugger shows that the object has not been sliced).
I have tried down casting and dynamic casting the pointer to B, but it slices away the data members of Bd.
Is there any way to call B::DoSomething without casting the pointer to Bd? And if not, if I have many derived classes of B (e.g. Bda, Bdb, Bdc etc), is there some way to use RTTI to know which derived class to cast it to?
You need to make DoSomething() a virtual function in both classes to get the polymorphic behavior you're after:
virtual void DoSomething(int i) { ...
You don't need to implement virtual functions in every sub class, as shown in the following example:
#include <iostream>
class A {
public:
virtual void print_me(void) {
std::cout << "I'm A" << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
virtual void print_me(void) {
std::cout << "I'm B" << std::endl;
}
};
class C : public A {
};
int main() {
A a;
B b;
C c;
A* p = &a;
p->print_me();
p = &b;
p->print_me();
p = &c;
p->print_me();
return 0;
}
Output:
I'm A
I'm B
I'm A
I'm setting a up an interface for various components of a framework in a personal project, and i've suddenly thought of something that i figured might be useful with an interface. My question is whether this is possible or not:
class a
{
public:
virtual class test = 0;
};
class b : public a
{
public:
class test
{
public:
int imember;
};
};
class c : public a
{
public:
class test
{
public:
char cmember; // just a different version of the class. within this class
};
};
sort of declaring a virtual class or pure virtual class, that is required to be defined within the derived object, so that you might be able to do something like this:
int main()
{
a * meh = new b();
a * teh = new c();
/* these would be two different objects, but have the same name, and still be able
to be referred to by an interface pointer in the same way.*/
meh::test object1;
teh::test object2;
delete meh;
delete teh;
return 0;
}
msvc++ throws me a bunch of syntax errors, so is there a way to do this, and i'm just not writing it right?
No, it isn't valid. In any case, C++ has no concept of virtual classes as such. You can probably achieve what you want by holding a pointer to a certain class with only pure virtual methods (although that isn't a requirement):
class ITest { /* full of pure virtual methods... maybe. */};
class a
{
public:
virtual ITest* someFunctionName()=0 ;
private:
ITest* test_;
};
Then you can decide to inherit from a, giving each implementation concrete implementations of ITest, or some other approach, such as deciding which implementation to use based on some constructor parameter, for example.
The keyword "virtual" merely means "table to dispatch function call.
What you proposed is not part of the language.
But you can approach it in another way, by chaining the object creation to proper virtual calls:
#include <iostream>
using namespace std;
class a
{
public:
class test
{
public:
virtual ~test() {} ///< required to have polimorphic behavior
virtual void hello() const =0;
};
virtual test* create_test()=0;
};
class b: public a
{
public:
class test_b: public a::test
{
virtual void hello() const
{ cout << "this is test_b at " << this << endl; }
};
virtual test* create_test()
{ return new test_b; }
};
class c: public a
{
public:
class test_c: public a::test
{
virtual void hello() const
{ cout << "this is test_c at " << this << endl; }
};
virtual test* create_test()
{ return new test_c; }
};
int main()
{
a* pa1 = new b;
a* pa2 = new c;
a::test* p1 = pa1->create_test();
a::test* p2 = pa2->create_test();
p1->hello();
p2->hello();
delete p2; delete p1;
delete pa2; delete pa1;
}