Skip to content

Commit 3fa80f3

Browse files
committed
cpp.cpp: virtual inheritance added
1 parent a9dc9cd commit 3fa80f3

File tree

4 files changed

+202
-122
lines changed

4 files changed

+202
-122
lines changed

c/cpp.cpp

Lines changed: 183 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1224,13 +1224,50 @@ void printCallStack()
12241224
class PureVirtualImplementedOtherBase
12251225
{
12261226
public:
1227-
1228-
void pureVirtualImplementedOtherBase()
1227+
void pureVirtual()
1228+
{
1229+
callStack.push_back("PureVirtualImplementedOtherBase::pureVirtual()");
1230+
}
1231+
private:
1232+
void privatePureVirtual()
12291233
{
1230-
callStack.push_back("PureVirtualImplementedOtherBase::pureVirtualOtherBase()");
1234+
callStack.push_back("PureVirtualImplementedOtherBase::privatePureVirtual()");
12311235
}
12321236
};
12331237

1238+
class DerivedAbtractAndImplementator : BaseAbstract, PureVirtualImplementedOtherBase
1239+
{
1240+
//public:
1241+
//void pureVirtual()
1242+
//{
1243+
//callStack.push_back("PureVirtualImplementedOtherBase::pureVirtual()");
1244+
//}
1245+
//private:
1246+
//void privatePureVirtual()
1247+
//{
1248+
//callStack.push_back("PureVirtualImplementedOtherBase::privatePureVirtual()");
1249+
//}
1250+
};
1251+
1252+
class MultipleInheritanceConflictBase1 {
1253+
public:
1254+
const static int is = 1;
1255+
int i;
1256+
void f(){}
1257+
};
1258+
1259+
class MultipleInheritanceConflictBase2 {
1260+
public:
1261+
const static int is = 2;
1262+
int i;
1263+
void f(){}
1264+
};
1265+
1266+
class MultipleInheritanceConflictDerived :
1267+
MultipleInheritanceConflictBase1,
1268+
MultipleInheritanceConflictBase2
1269+
{};
1270+
12341271
class BaseProtected
12351272
{
12361273
public:
@@ -1258,8 +1295,7 @@ void printCallStack()
12581295
//public Derived, //WARN cannot use BasePrivate inside: ambiguous
12591296
protected BaseProtected,
12601297
private BasePrivate,
1261-
public BaseAbstract,
1262-
public PureVirtualImplementedOtherBase
1298+
public BaseAbstract
12631299
{
12641300
public:
12651301

@@ -6038,163 +6074,197 @@ int main(int argc, char **argv)
60386074
}
60396075
}
60406076

6041-
//#overridding
6077+
/*
6078+
#inheritance
6079+
*/
60426080
{
6043-
Class c;
6044-
Class* cp = &c;
6081+
//#overridding
6082+
{
6083+
Class c;
6084+
Class* cp = &c;
60456085

6046-
c.i = 0;
6047-
c.Class::i = 0;
6048-
cp->Class::i = 0;
6049-
c.Base::i = 1;
6050-
c.BaseAbstract::i = 2;
6086+
c.i = 0;
6087+
c.Class::i = 0;
6088+
cp->Class::i = 0;
6089+
c.Base::i = 1;
6090+
c.BaseAbstract::i = 2;
60516091

6052-
assert(c.i == 0);
6053-
assert(c.Class::i == 0);
6054-
assert(cp->Class::i == 0);
6092+
assert(c.i == 0);
6093+
assert(c.Class::i == 0);
6094+
assert(cp->Class::i == 0);
60556095

6056-
assert(c.Base::i == 1);
6057-
assert(cp->Base::i == 1);
6096+
assert(c.Base::i == 1);
6097+
assert(cp->Base::i == 1);
60586098

6059-
assert(c.BaseAbstract::i == 2);
6060-
assert(cp->BaseAbstract::i == 2);
6099+
assert(c.BaseAbstract::i == 2);
6100+
assert(cp->BaseAbstract::i == 2);
60616101

6062-
//c.iAmbiguous = 0;
6063-
//ERROR ambiguous
6064-
c.Base::iAmbiguous = 0;
6065-
c.BaseAbstract::iAmbiguous = 0;
6102+
//c.iAmbiguous = 0;
6103+
//ERROR ambiguous
6104+
c.Base::iAmbiguous = 0;
6105+
c.BaseAbstract::iAmbiguous = 0;
60666106

6067-
callStack.clear();
6068-
c.method();
6069-
assert(callStack.back() == "Class::method()");
6070-
//c.methodAmbiguous();
6071-
//ERROR ambiguous
6072-
callStack.clear();
6073-
c.Base::methodAmbiguous();
6074-
assert(callStack.back() == "Base::methodAmbiguous()");
6107+
callStack.clear();
6108+
c.method();
6109+
assert(callStack.back() == "Class::method()");
6110+
//c.methodAmbiguous();
6111+
//ERROR ambiguous
6112+
callStack.clear();
6113+
c.Base::methodAmbiguous();
6114+
assert(callStack.back() == "Base::methodAmbiguous()");
60756115

6076-
callStack.clear();
6077-
c.BaseAbstract::methodAmbiguous();
6078-
assert(callStack.back() == "BaseAbstract::methodAmbiguous()");
6116+
callStack.clear();
6117+
c.BaseAbstract::methodAmbiguous();
6118+
assert(callStack.back() == "BaseAbstract::methodAmbiguous()");
6119+
}
60796120

60806121
/*
6081-
#virtual inheritance
6122+
#virtual
60826123
6083-
<http://en.wikipedia.org/wiki/Virtual_inheritance>
6124+
Virtual: decides on runtime based on object type.
60846125
6085-
TODO
6086-
*/
6087-
}
6126+
<http://stackoverflow.com/questions/2391679/can-someone-explain-c-virtual-methods>
60886127
6089-
/*
6090-
#virtual
6128+
#pure virtual function
6129+
6130+
Cannot instantiate this class
6131+
6132+
Can only instantiate derived classes that implement this.
6133+
6134+
If a class has a pure virtual method is called as an *abstract class* or *interface*.
6135+
6136+
In Java there is a language difference between those two terms,
6137+
and it might be a good idea to differentiate them when speaking about C++:
60916138
6092-
Virtual: decides on runtime based on object type.
6139+
- interface: no data
6140+
- abstract: data
60936141
6094-
<http://stackoverflow.com/questions/2391679/can-someone-explain-c-virtual-methods>
6142+
#polymorphism
60956143
6096-
#pure virtual function
6144+
- loop an array of several dereived classes
6145+
- call a single base class method
6146+
- uses the correct derived override
60976147
6098-
Cannot instantiate this class
6148+
Implementation: *vtable* is used to implement this.
60996149
6100-
Can only instantiate derived classes that implement this.
6150+
#vtable
61016151
6102-
If a class has a pure virtual method is called as an *abstract class* or *interface*.
6152+
<http://en.wikipedia.org/wiki/Virtual_method_table>
61036153
6104-
In Java there is a language difference between those two terms,
6105-
and it might be a good idea to differentiate them when speaking about C++:
6154+
Whenever you create a pointer to a class with a virtual method,
6155+
that pointer points to a pointer that identifies the class type,
6156+
and points to the correct method.
61066157
6107-
- interface: no data
6108-
- abstract: data
6158+
Consequence: every call to a virtual methods means:
61096159
6110-
#polymorphism
6160+
- an extra pointer dereference
6161+
- an extra pointer stored in memory
61116162
6112-
- loop an array of several dereived classes
6113-
- call a single base class method
6114-
- uses the correct derived override
6163+
Also virtual functions cannot be inlined.
61156164
6116-
Implementation: *vtable* is used to implement this.
6165+
#Static interfaces
61176166
6118-
#vtable
6167+
It is possible to assert that interfaces are implemented without dynamic vtable overhead via CRTP:
61196168
6120-
<http://en.wikipedia.org/wiki/Virtual_method_table>
6169+
- <http://stackoverflow.com/questions/2587541/does-c-have-a-static-polymorphism-implementation-of-interface-that-does-not-us>
61216170
6122-
Whenever you create a pointer to a class with a virtual method,
6123-
that pointer points to a pointer that identifies the class type,
6124-
and points to the correct method.
6171+
- <http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism>
61256172
6126-
Consequence: every call to a virtual methods means:
6173+
#CRTP
61276174
6128-
- an extra pointer dereference
6129-
- an extra pointer stored in memory
6175+
Curiously recurring template pattern.
61306176
6131-
Also virtual functions cannot be inlined.
6177+
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Static_polymorphism>
6178+
*/
6179+
{
6180+
//BaseAbstract b;
6181+
//ERROR: BaseAbstract cannot be instantiated because it contains a pure virtual method
6182+
//virtual = 0;. That method must be implemented on derived classes
61326183

6133-
#Static interfaces
6184+
//even if you can't instantiate base, you can have pointers to it
6185+
{
6186+
BaseAbstract* bap = new Class;
6187+
//BaseAbstract* bap = &c;
6188+
//SAME
61346189

6135-
It is possible to assert that interfaces are implemented without dynamic vtable overhead via CRTP:
6190+
callStack.clear();
6191+
bap->method();
6192+
assert(callStack.back() == "BaseAbstract::method()");
6193+
//base method because non-virtual
61366194

6137-
- <http://stackoverflow.com/questions/2587541/does-c-have-a-static-polymorphism-implementation-of-interface-that-does-not-us>
6195+
callStack.clear();
6196+
bap->virtualMethod();
6197+
assert(callStack.back() == "Class::virtualMethod()");
6198+
//class method because virtual
61386199

6139-
- <http://en.wikipedia.org/wiki/Template_metaprogramming#Static_polymorphism>
6200+
delete bap;
6201+
}
61406202

6141-
#CRTP
6203+
{
6204+
//you can also have BaseAbstract&
6205+
Class c;
6206+
BaseAbstract& ba = c;
61426207

6143-
Curiously recurring template pattern.
6208+
callStack.clear();
6209+
ba.method();
6210+
assert(callStack.back() == "BaseAbstract::method()");
61446211

6145-
<http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern#Static_polymorphism>
6146-
*/
6147-
{
6148-
//BaseAbstract b;
6149-
//ERROR: BaseAbstract cannot be instantiated because it contains a pure virtual method
6150-
//virtual = 0;. That method must be implemented on derived classes
6212+
callStack.clear();
6213+
ba.virtualMethod();
6214+
assert(callStack.back() == "Class::virtualMethod()");
6215+
}
61516216

6152-
//even if you can't instantiate base, you can have pointers to it
6153-
{
6154-
BaseAbstract* bap = new Class;
6155-
//BaseAbstract* bap = &c;
6156-
//SAME
6217+
{
6218+
Class c = Class();
6219+
Base* bp = &c;
6220+
bp = bp->covariantReturn();
61576221

6158-
callStack.clear();
6159-
bap->method();
6160-
assert(callStack.back() == "BaseAbstract::method()");
6161-
//base method because non-virtual
6222+
callStack.clear();
6223+
bp->virtualMethod();
6224+
assert(callStack.back() == "Class::virtualMethod()");
61626225

6163-
callStack.clear();
6164-
bap->virtualMethod();
6165-
assert(callStack.back() == "Class::virtualMethod()");
6166-
//class method because virtual
6226+
//classPtr = basePtr->covariantReturn();
6227+
//ERROR
6228+
//conversion from Base to Class
6229+
}
61676230

6168-
delete bap;
6231+
/*
6232+
It is not possibleto implement pure virtual methods on another base class:
6233+
they must be implemented on the Derived class.
6234+
*/
6235+
{
6236+
//DerivedAbtractAndImplementator d; //ERROR
6237+
}
61696238
}
61706239

6171-
{
6172-
//you can also have BaseAbstract&
6173-
Class c;
6174-
BaseAbstract& ba = c;
6240+
/*
6241+
#multiple inheritance
61756242
6176-
callStack.clear();
6177-
ba.method();
6178-
assert(callStack.back() == "BaseAbstract::method()");
6243+
In C++, if a member of an object or static variable of a class
6244+
comes from two base classes, an ambiguity occurs and the program does not
6245+
compile.
61796246
6180-
callStack.clear();
6181-
ba.virtualMethod();
6182-
assert(callStack.back() == "Class::virtualMethod()");
6247+
This just makes multiple inheritance very insane, since the addition of
6248+
new fields in a Base class can break existing code on Derived classes.
6249+
*/
6250+
{
6251+
//MultipleInheritanceConflictDerived::is;
6252+
//MultipleInheritanceConflictDerived().i;
6253+
//MultipleInheritanceConflictDerived().f();
61836254
}
61846255

6185-
{
6186-
Class c = Class();
6187-
Base* bp = &c;
6188-
bp = bp->covariantReturn();
6256+
/*
6257+
#dreaded diamond
61896258
6190-
callStack.clear();
6191-
bp->virtualMethod();
6192-
assert(callStack.back() == "Class::virtualMethod()");
6259+
#virtual inheritance
61936260
6194-
//classPtr = basePtr->covariantReturn();
6195-
//ERROR
6196-
//conversion from Base to Class
6197-
}
6261+
Solves the dreaded diamond problem.
6262+
6263+
Has nothing to do with the `virtual` keyword for methods:
6264+
everything is done at compile time in thie usage.
6265+
6266+
<http://stackoverflow.com/questions/21558/in-c-what-is-a-virtual-base-class>
6267+
*/
61986268
}
61996269

62006270
//#friend

0 commit comments

Comments
 (0)