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 ext2 : 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
$
cl cat 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 22 April 2003.