I have the following classes, and I'm trying to access a base member using an object of class H, and I get an H::a is ambiguous warning.
class E {
public:
E() : a(11) { }
int a;
};
class F : public E {
public:
F() : b(22) { }
int b;
};
class G : public E {
public:
G() : c(33) { }
int c;
};
class H: public F, public G {
public:
H() : d(44) { }
int d;
};
I tried making the data member a static, but then it doesn't let me initialize it in the base constructor. What's a solution to these two problems?
Class "H" has two variables called "a", one derived from F and one from G. You can either use a qualifier,
H::a
or you can use the "virtual" inheritance specifier (see https://stackoverflow.com/a/419999/257645)
#include <iostream>
struct A {
int a;
};
struct B : virtual public A {
};
struct C : virtual public A {
};
struct D : virtual public B, virtual public C {
void d1() { a = 1; }
void d2() { a = 2; }
};
int main() {
D d;
d.d1();
d.d2();
std::cout << d.a << std::endl;
}
http://ideone.com/p3LPe0
Related
class A {
class B {
public:
void doSomething();
};
class C : public B {};
class D : public B {};
};
// In B.hpp file
class hello {
class hi {};
class world : public hi, public C {};
};
// In main.cpp file
int main() {
world my_world;
my_world.doSomething();
}
In this code, I want to remove the inheritance between class B and class C. When I instantiate class world, I should still be able to access doSomthing() method from class world.
Is there a way to implement "Has a" method which is as per my understanding a pointer to the base class?
As I mentioned in a comment, the code proposed in the question is incorrect as written. Class members default to being private, so you need to explicitly mark them as public if you want to be able to access them from outside of that class's context. Furthermore, you are missing some scope resolution operators and at least one semicolon. This is the corrected version of your current code. I've also added some code so that the doSomething function has an observable effect—i.e., so that it actually does something.
class A
{
public:
class B
{
public:
void doSomething() { std::cout << "Hello, world!\n"; };
};
class C : public B
{ };
class D : public B
{ };
};
class hello
{
public:
class hi
{ };
class world : public hi, public A::C
{ };
};
int main()
{
hello::world my_world;
my_world.doSomething();
}
Inheritance means "is-a", whereas composition means "has-a". What you have now (as shown above) is inheritance, so you're modeling "is-a". If you want "has-a" instead, So, you want composition. Simply change C to have a member of type B:
class A
{
public:
class B
{
public:
void doSomething() { std::cout << "Hello, world!\n"; };
};
class C
{
public:
B b;
};
class D : public B
{ };
};
class hello
{
public:
class hi
{ };
class world : public hi, public A::C
{ };
};
int main()
{
hello::world my_world;
my_world.b.doSomething();
}
Now, in this code, C has a B. It is named b (but you could name it whatever you wanted).
If you don't want to require that doSomething be accessed from the b member, then you'll need to write a wrapper function. That would even allow you to keep the b member private.
#include <iostream>
class A
{
public:
class B
{
public:
void doSomething() { std::cout << "Hello, world!\n"; };
};
class C
{
B b;
public:
void doSomething() { b.doSomething(); }
};
class D : public B
{ };
};
class hello
{
public:
class hi
{ };
class world : public hi, public A::C
{ };
};
int main()
{
hello::world my_world;
my_world.doSomething();
}
//In file1.hpp
class A
{
protected:
class B
{
public:
B () {};
};
};
// In file2.hpp
class C
{
public:
void getValue()
{
D obj; ---- error: no matching function for call to D
printf("%d\n",obj.c);
}
class D : public A::B
{
friend class C; -- I tried writing this but still no luck.
public:
D(int a, int b) : c(a), d(b) {}
virtual ~D() {}
//something
private:
int c; int d;
};
class E : public D
{
E() : D(1,2) {}
virtual ~E() {}
};
}
int main()
{
C::E obj;
}
In the public function, getValue I want to access the private member variables of the class D which are (c and d). How can I do that? I tried putting "friend class C" inside class D and then tried creating an object of class D inside getValue function but instead of getting a value like c=5 or d=6, I always get 0.
If I print the value in the following area, I get the correct value. I won't be able to show you how getValue is called but just imagine that it is called somehow. I just need to print c,d in that.
D(int a, int b)
: c(a), d(b) {};
EDIT: At the time of instantiation in getValue, I do something like this
D obj; --- error: no matching function for call to D
Let take the following example:
#include <iostream>
//In file1.hpp
class A
{
protected:
class B
{
public:
B () = default;
};
friend class C; // <-- bad idea
};
// In file2.hpp
class C
{
public:
void getValue()
{
// Creating an object E?
E objE;
// Access c and d
std::cout << "c:" << objE.c << ", d:" << objE.d << std::endl;
}
class D : public A::B // <-- bad idea?
{
public:
D(int a, int b): c(a), d(b) {}
virtual ~D() {}
//something
private:
int c; // dangerous to not initialize basic types
int d;
friend class C; // <-- bad idea
};
class E : public D
{
public:
E() : D(1,2) {}
virtual ~E() {}
};
};
int main()
{
C objC;
objC.getValue();
}
( you can run it here: https://onlinegdb.com/hNfm7Pvg0f )
First is, to have an instance of E to access in C::getValue, so I instantiated an object.
private and protected indicate that those properties and methods are not available publicly (encapsulation) and that is exactly what you are trying to do. You can make exceptions with friend keyword, but that is rarely a good idea (I probably use it twice in my 20 years carrier). But hey! it works.
I came across this code in a past exam:
#include <iostream>
class cls1
{
protected:
int x;
public:
cls1()
{
x = 13;
}
};
class cls2 : public cls1
{
int y;
public:
cls2()
{
y = 15;
}
int f(cls2 ob)
{
return (ob.x + ob.y);
}
};
int main()
{
cls2 ob;
std::cout << ob.f(ob);
return 0;
}
This works just fine and outputs 28. The problem is, it seems to contradict with this code (found in another exam):
#include <iostream>
class B
{
protected:
int x;
public:
B(int i = 28)
{
x = i;
}
virtual B f(B ob)
{
return x + ob.x + 1;
}
void afisare()
{
std::cout << x;
}
};
class D : public B
{
public:
D(int i = -32)
: B(i)
{
}
B f(B ob)
{
return x + ob.x - 1;/// int B::x is protected within this context
}
};
int main()
{
B *p1 = new D, *p2 = new B, *p3 = new B(p1->f(*p2));
p3->afisare();
return 0;
}
It's the same type of hierarchy, but one has access to ob.x and the other one doesn't. Can someone explain to me why that is?
The difference is, in the 1st case the protected member is accessed through the derived class. In the 2nd case the protected member is accessed through the base class, which is not allowed.
For protected members,
(emphasis mine)
A protected member of a class is only accessible
2) to the members and friends (until C++17) of any derived class of that class, but only when the class of the object through which the protected member is accessed is that derived class or a derived class of that derived class:
struct Base {
protected:
int i;
private:
void g(Base& b, struct Derived& d);
};
struct Derived : Base {
void f(Base& b, Derived& d) { // member function of a derived class
++d.i; // OK: the type of d is Derived
++i; // OK: the type of the implied '*this' is Derived
// ++b.i; // error: can't access a protected member through
// Base (otherwise it would be possible to change
// other derived classes, like a hypothetical
// Derived2, base implementation)
}
};
class B :I'm in this type of scenario in my project, where I'm in x()function of base class A and need to access the data y from derived class C.
I have declared the object of derived class C and using obj_c i got to the x() function
class A
{
private :
public :
//.....
void x()
{
cout << y ;
}
//.....
};
class B : public A
{
public :
//.....
protected :
//.....
private :
//.....
};
class C : public B
{
public :
//.....
protected :
int y = 10 ;
private :
//.....
};
int main()
{
C obj_c ;
obj_c.x();
}
Place the declaration of y inside the base class. After all, the way you've written your code, A needs to contain a y in order to function.
The derived class can then assign the value by passing it up to A at construction.
class A {
public:
void x() { cout << y; };
protected:
A(int value) : y(value) {}
int y;
}
class B : public A
{
protected:
B(int value) : A(value) {}
}
class C : public B
{
public:
C() : B(10) {}
}
As C inherits from B and B inherits from A, then make function virtual in class. implement it in C and call it directly.
The idea of a base class is that A might be used even if C didn't exist. So where is A going to get y?
What you do in those cases is the Template Method design pattern:
A assumes that inheriting classes will provide a y by requiring that they implement a get_y() method:
#include <iostream>
class A
{
private :
protected:
virtual int get_y() = 0;
public :
//.....
void x()
{
std::cout << get_y() << std::endl;
}
//.....
};
class B : public A
{
public :
//.....
protected :
//.....
private :
//.....
};
class C : public B
{
public :
//.....
protected :
int get_y()
{
return 10;
}
private :
//.....
};
int main()
{
C obj_c ;
obj_c.x();
}
Does it important in which order you inheritence abstact classes, which has same functions ?
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
class C : public A {
public:
virtual void f1() { globalF1_C(); }
};
class D : public A, public B, public C { };
class E : public A, public C, public B { };
Does D and E classes would be the same, if I would write it like below:
class D{
public:
virtual void f1() { globalF1_C(); }
virtual void f2() { globalF2_B(); }
};
class E {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
PS. I inheritence class A into class D and class E just in case I can forget make some realization of class A's function.
No there are not the same. Besides an invalid C++ code provided, we can say :
In the first case your classes D and E have two method f1() (one inherited from B and one inherited from C) and one method f2() (inherited from C). If you would be able to construct a D object name d, then d.f1() would be reported as an ambiguity that you would need to clarify either this way : d.B::f1() or this one d.C::f1().
While in the second case your classes will only have two methods f1() and f2().
#include <iostream>
using namespace std;
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { cout << "B::f1()" << endl; }
virtual void f2() { cout << "B::f2()" << endl; }
};
class C : public A {
public:
virtual void f1() { cout << "C::f1()" << endl; }
virtual void f2() { cout << "C::f2()" << endl; }
};
class D : public B, public C { };
class E : public C, public B { };
int main() {
D d;
// d.f1(); // t.cpp:28:5: error: member 'f1' found in multiple base classes of different types
d.C::f1();
d.B::f1();
}
NO, the first version of D & E won't compile either. there would be ambiguity in resolving f1 and f2 in D and E