Ctype i; i.f();
where is f()
?
C = i's declared class (Ctype, in this case). while C::f() does not exist if C does not have a parent error: f() not found. C = C's parent class
f()
.
i
's declared type.
i
's static type.
class VirtualFileSystem { status open(string name, mode m) { } } class ext2 : VirtualFileSystem { status open(string name, mode m) { // whatever } }
static ext2 linux_fs VirtualFileSystem * vfs = &linux_fs vfs->open("joe", VirtualFileSystem::read)
where is open()
?
VirtualFileSystem
, which is not what we
want.
vfs
's declared (or static) type is VirtualFileSystem
.
C = i's value's declared class (ext2) while C::f() does not exist if C does not have a parent error: f() not found. C = C's parent class
Dynamic look-up correctly finds ext2::open()
.
virtual
keyword
makes the member function virtual.
class VirtualFileSystem virtual status open(...);
virtual
when defining member functions outside the
class.
virtualVirtualFileSystem::status ext2::open(...) { ... }
virtual
is a per-function keyword.
virtual
keyword necessary.
class DeviceInterface { bool initialized(void); virtual status open(...) { } } class VirtualFileSystem : DeviceInterface { virtual status rename(...) { } } class ext2 : VirtualFileSystem { status open(...) { ... } status rename(...) { ... } } class ntfs : VirtualFileSystem { virtual status open(...) { ... } virtual bool initialized(void); }
VirtualFileSystem::open()
is virtual.
DeviceInterface::open()
is virtual.
class DeviceInterface bool initialized(void) { } class VirtualFileSystem : DeviceInterface virtual bool initialized(void) { } class HFS : VirtualFileSystem bool initialized(void) { } static HFS mac_fs VirtualFileSystem & vfs = mac_fs DeviceInterface * dip = &mac_fs
vfs.initialized()
?
dip->initialized()
?
class DeviceInterface bool initialized(void) { } class VirtualFileSystem : DeviceInterface virtual bool initialized(void) { } class HFS : VirtualFileSystem bool initialized(void) { } static HFS mac_fs VirtualFileSystem & vfs = mac_fs DeviceInterface * dip = &mac_fs
Where is vfs.initialized()
?
vfs
has static type VirtualFileSystem
.initialized()
is virtual in VirtualFileSystem
.vfs
has dynamic type HFS
.HFS::initialized()
.
Where is dip->initialized()
?
dip
has static type DeviceInterface
.initialized()
is non-virtual in DeviceInterface
.DeviceInterface::initialized()
.
class Number { ... } class Complex : Number { ... } void f() Number * np = new Complex() delete np
What happens when delete np
is called?
Number::~Number
is not virtual, static look-up is used and
Complex::~Complex
is never called.
$ cat t.cc struct Number virtual void output(ostream &) const; struct Complex : Number void output(ostream &) const cout << "Hello from Complex::output().\n" int main() Complex c ; c.output(cout) $ g++ -o t t.cc /tmp/f.o(.gnu.linkonce.d._vt.7Complex+0xc): undefined reference to Number::output(ostream &) /tmp/f.o: In function Complex type_info function: /tmp/f.o(.gnu.linkonce.t.__tf7Complex+0x1c): undefined reference to Number type_info function /tmp/f.o: In function Number::Number(void): /tmp/f.o(.Number::gnu.linkonce.t.(void)+0x8): undefined reference to Number virtual table collect2: ld returned 1 exit status $ CC -c t.cc "t.cc", line 15: Warning: Complex::output hides the virtual function Number::output(basic_ostream<char, char_traits<char>>&) 1 Warning(s) detected. $
$ cat t.cc struct Number virtual void output(ostream &) const { }; struct Complex : Number void output(ostream &) const cout << "Hello from Complex::output().\n"; int main() Complex c ; c.output(cout) $ g++ -o t t.cc $ CC -o t t.cc $
struct A virtual void hi(unsigned) std::cout << "in A::hi(unsigned)" struct B : A void hi(int) std::cout << "in B::hi(int)" struct C : B void hi(unsigned) std::cout << "in C::hi(unsigned)" int main() A * ap = new C() B * bp = new C() ap->hi(1) bp->hi(1)
B::hi(int)
is not virtual.
void B::hi(int)
does not match
void A::hi(unsigned)
.
C::hi(unsigned)
is virtual.
void C::hi(unsigned)
matches
void A::hi(unsigned)
.
$ g++ -o t -ansi -pedantic -Wall t.cc $ ./t in C::hi(unsigned) in B::hi(int) $ CC -o t t.cc "t.cc", line 13: Warning: B::hi hides the virtual function A::hi(unsigned). 1 Warning(s) detected. $ ./t in C::hi(unsigned) in B::hi(int) $
const
struct A virtual void hi(void) { ... } struct B : A { void hi(void) const { ... } struct C : B { void hi(void) { ... } int main() { A * ap = new C() B * bp = new C() ap->hi() // ?::hi() bp->hi() // ?::bye() }
const
member-function modifier takes part too.
C::hi()
B::bye()
void hi(void)
does not match
void hi(void) const
.
$ cat t.cc struct shape { ... } struct circle : shape { ... } struct A virtual void hi(shape *) { ... } struct B : A void hi(circle *) { ... } struct C : B void hi(shape * ) { ... } int main() A * ap = new C() B * bp = new C() circle * cp ap->hi(cp) bp->hi(cp) $ g++ -o t -ansi -pedantic -Wall t.cc $ ./t in C::hi(shape *) in B::hi(circle *) $ CC -o t t.cc $ ./t in C::hi(shape *) in B::hi(circle *) $
struct Number { virtual void output(ostream &) = 0; };
abstract
again in the child.
This page last modified on 21 May 2004.