Why does the follwing code produce this error even though c is a struct and has a public inheritance by default??
struct c
{
protected:
int i;
public:
c(int ii=0):i(ii){}
virtual c *fun();
};
c* c::fun(){
cout<<"in c";
return &c();
}
class d : c
{
public:
d(){}
d* fun()
{
i = 9;
cout<<"in d"<<'\t'<<i;
return &d();
}
};
int main()
{
c *cc;
d dd;
cc = ⅆ
cc->fun();
}
You need:
class d : public c
class inheritance is private by default.
When you privately inherit from a class or a struct, you explicitly say, among other things, that direct conversion from a derived type to a base type isn't possible.
Related
The code below gives a compile-time error but when I remove the keyword "virtual" from below it works fine. I know that virtual inheritance is done to avoid multiple copies of base class members, but what is the significance of the keyword "virtual" here??
#include<iostream>
using namespace std;
class A {
int a;
A() {
cout<<"I am A\n";
a = 1;
}
public :
friend class B;
};
class B : virtual public A {
int b;
public :
B() {
cout<<"I am B\n";
b = 2;
}
};
class C : public B {
int c;
public :
C() {
cout<<"I am C\n";
c = 3;
}
};
int main()
{
C var;
return 0;
}
Initializaion of virtual base classes follows different logic than regular base classes.
From https://en.cppreference.com/w/cpp/language/derived_class#Virtual_base_classes:
All virtual base subobjects are initialized before any non-virtual base subobject, so only the most derived class calls the constructors of the virtual bases in its member initializer list:
In your case, the constructor of C can be thought of as:
C() : A(), B() {
cout<<"I am C\n";
c = 3;
}
That is a problem since A() is declared private.
When A is a regular base class of B, C() can be thought of as:
C() : B() { // No A()
cout<<"I am C\n";
c = 3;
}
That is not a problem given your posted code.
In Primer c++ 5th
class A {
public:
A() : a(1) {}
virtual ~A() = default;
private:
int a;
};
class B : public A {
public:
B() : b(2) {}
private:
int b;
};
class C : public B {
public:
C() : c(3) {}
private:
int c;
};
//class D : public B, public A { cause error
// public:
// D() : d(4) {}
// private:
// int d;
//};
int main()
{
//A *pa = new C;
//B *pb = dynamic_cast<B*>(pa); //1st case
B *pb = new B;
C *pc = dynamic_cast<C*>(pb); //2nd case
cout << pc << endl;
//A *pa = new D;
//B *pb = dynamic_cast<B*>(pa); //3rd case
}
//output: 0 cast failure
Q1:
Here in the above code .I can understand why the 2nd case doesn't work, but
the type of pb-pointed object is B which is the public base class of C .And this is the 2nd situation of what's said in Primer c++.
So why the 2nd case doesn't work while primer c++ said this kind of cast will succeed?
Q2:
the 3rd case. Errors occurred during compilation
error: āAā is an ambiguous base of āDā
What does this error mean?
in your second example you create a class B, B is a base class for C.
so you can't cast a base class to some derived class.
this will work:
B *pb = new C();
C *pc = dynamic_cast<C*>(pb);
regarding 3rd example D derive from B and A, but B also derive from A, this make problems for compiler. you try to derive 2 times for A, the compiler will not know what function A to use, the base A or the derived version of B.
al
you should read more about base and derived classes.
From https://en.cppreference.com/w/cpp/language/dynamic_cast:
dynamic_cast < new_type > ( expression )
3) If new_type is a pointer or reference to Base, and the type of expression is a pointer or reference to Derived, where Base is a unique, accessible base class of Derived, the result is a pointer or reference to the Base class subobject within the Derived object pointed or identified by expression. (Note: an implicit conversion and static_cast can perform this conversion as well.)
Sample code:
#include <iostream>
using namespace std;
class A {
//public:
// virtual ~A() {
//
// }
};
class B : public A {
};
class C : public B {
};
class D : public B, public A {
};
int main()
{
D* pd = new D;
if (B* pa = dynamic_cast<B*>(pd)) {
cout << "1";
}
return 0;
}
No error or warning under VC++
warning: direct base 'A' inaccessible in 'D' due to ambiguity under gcc, link
Shouldn't I expect a compile error?
Now I find that if I try to convert D* to A*, a error would occur, but as mentioned above, from D* to B*, no error.
int main()
{
D* pd = new D;
if (A* pa = dynamic_cast<A*>(pd)) {
cout << "1";
}
return 0;
}
link
In that context, unique means that Derived contains new_type only once, not that Derived derives from a single base class.
So, in your example, B is unique, because D contains it only once.
In your example, D contains A twice (once directly, and once through B), so a cast to A cannot be made, as A is not unique.
Note, that "containment" what it counts. So, in this example, C derives from Base twice, yet it is fine, as Base is inherited with the keyword virtual:
struct Base { };
struct A: virtual Base { };
struct B: virtual Base { };
struct C: A, B { };
int main() {
C c;
dynamic_cast<Base &>(c);
}
(If I haven't used virtual, then Base would have been ambiguous)
Note: I'd use static_cast instead, as it can do the cast in this case as well. Using dynamic_cast is a little bit misleading here, as the cast will be done compile-time, and not run-time.
The warning causes by indirect base class issue in multiple-inheritance model. D has two copies of base class A, one directly and one indirectly via B. When a base class is specified as a virtual base (same as #geza example), there is only one copy of base class' data members shared between virtual base classes.
class A {
public:
A() {}
};
class B : virtual public A {
public:
B() : A() {}
};
class C : public B, virtual public A {
public:
C() : B() {}
};
int main()
{
A* pa = static_cast<A *>(new C()); // no more warning since A is virtual
return 0;
}
It's well explained here: Multiple Base Classes.
I have the following design:
- one class A that has a protected member of class M.
- one class B that inherits from A and has a pointer to an object of class C
- one class C that needs to have access to the member of the class A
class A {
public:
A() : _member(0) {}
~A() { delete _member }
protected:
M _member;
}
class B : public A {
public:
B(){}
~B(){}
protected:
C* c;
}
class C {
// C needs to have access to _member
}
What design should be more appropriate to solve this issue ?
In pure OO terms, allowing a class to directly access the internal fields of another class is bad practice.
That said, C++ is not a pure OO language, and does allow for this (among other important deviations from OO).
To allow access to a private member to another class, you must designate that class to be a friend. Friendship, however is not passed to derived classes, therefore you must upcast the class to the type you need.
This is your simplest solution:
class A {
public:
A() : _member(0) {}
~A() { delete _member }
protected:
friend class C;
M _member;
}
class B : public A {
public:
B(){ c = new C(this); } // this call will cast the B* to an A* (important)
~B(){ delete c;}
protected:
C* c;
}
class C {
public:
C(A* a) { _a->_member = new M(); } //Now C can directly access _member in A
}
In such a way, any object derived from A can be turned back into an A* and used to access _member.
However, as previously stated, any classes derived from C will not gain access to _member, as friendship is not inherited, so a more comprehensive solution is required:
class M {
public:
void Foo() { printf("Foo called\n"); }
};
class A {
M* m;
friend class C;
public:
A():m(0) { ; }
};
class B :public A {
int id;
public:
B() { id = 0; }
};
class C {
public:
C() { _a = 0; }
C(A* a) { _a = a; }
protected:
M* getM() { return _a->m; }
void setM(M* m_) { _a->m = m_; }
private:
A* _a;
};
class D : public C {
public:
D(B* b): C(b) {
}
void Foo() {
setM(new M());
getM()->Foo();
delete getM();
setM(nullptr);
}
};
int main()
{
B* b = new B();
D d(b);
d.Foo();
delete b;
getchar();
return 0;
}
In this way, no classes derived from A provide direct access to _member, and no classes derived from C have direct access, but the member variable can still be accessed via C's protected API. This also prevents other external objects accessing it.
Make C a friend of A:
class A {
friend class C;
/*and so on*/
Then C can see all member variables and functions in A, even if they are private.
Although I made the members of both base and derived classes public, Why does the conversion says that it is inaccessible?
class B
{
public:
int var;
};
class D: private B
{
public:
int var;
};
int main()
{
D d;
Base &b = d; //my error
}
You can't convert from a derived class to a non-public base class (well, outside the class itself anyway). Private inheritance is typically used as a form of composition, not for substitution so there's no need to convert to the base. In your case it looks like you want substitution so you should use public inheritance.
Try this:
#include <iostream>
class B
{
public:
int var;
};
class D: public B
{
public:
int var;
};
int main()
{
D d;
B &b = d; //my error
}
What you are trying to do won't work with private inheritance. Also note that your base class is known as B and not Base.
Regards,
Dennis M.