i.n()
, name look-up starts with class given in the
declaration for i
and goes up the inheritance hierarchy
i
struct Number { void output(ostream &) const { cerr << "Number::output() not defined.\n"; } }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." Complex * cp = new Complex; cp->output(cout); // prints "Hello from Complex::output()." Number * np = cp; np->output(cout); // prints "Number::output() not defined." }
np
has static type Number *
, np->output(cout)
calls
Number::output()
Complex::output()
virtual
keyword indicates the function should
be looked-up starting at the dynamic type
struct Number { virtual void output(ostream &) const { cerr << "Number::output() not defined.\n"; } }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." Complex * cp = new Complex; cp->output(cout); // prints "Hello from Complex::output()." Number * ap = cp; ap->output(cout); // prints "Hello from Complex::output()." }
virtual
keyword, look-up starts at the static type.
virtual
is a per-function keyword - a class can mix virtual and
non-virtual functions
struct Number { virtual void output(ostream &) const { cerr << "Number::output() not defined.\n"; } void print_type(void) const { cout << "A generic number.\n"; } }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } void print_type(void) const { cout << "A complex number.\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." n.print_type(); // prints "A generic number." Complex * cp = new Complex; cp->output(cout); // prints "Hello from Complex::output()." cp->print_type(); // prints "A complex number." Number * ap = cp; ap->output(cout); // prints "Hello from Complex::output()." ap->print_type(); // prints "A generic number." }
virtual
keyword necessary
struct Number { virtual void output(ostream &) const { cerr << "Number::output() not defined.\n"; } void print_type(void) const { cout << "A generic number.\n"; } }; struct Floating_point : Number { void output(ostream &) const { cout << "Hello from Floating_point::output().\n"; } void print_type(void) const { cout << "A floating-point number.\n"; } }; struct Transfinite : Floating_point { void output(ostream &) const { cout << "Hello from Transfinite::output().\n"; } void print_type(void) const { cout << "A transfinite number.\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." n.print_type(); // prints "A generic number." Floating_point * fp = new Floating_point; fp->output(cout); // prints "Hello from Floating_point::output()." fp->print_type(); // prints "A floating-point number." Number * np = fp; np->output(cout); // prints "Hello from Floating_point::output()." np->print_type(); // prints "A generic number." delete fp; fp = new Transfinite; fp->output(cout); // prints "Hello from Transfinite::output()." fp->print_type(); // prints "A floating-point number." np = fp; np->output(cout); // prints "Hello from Transfinite::output()." np->print_type(); // prints "A generic number." }
struct Number { void output(ostream &) const { cerr << "Number::output() not defined.\n"; } }; struct Complex : Number { virtual void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." Complex * cp = new Complex; cp->output(cout); // prints "Hello from Complex::output()." Number * np = cp; np->output(cout); // prints "Number::output() not defined." }
struct Number { virtual void output(ostream &) const { cerr << "Number::output() not defined.\n"; } }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Number n; n.output(cout); // prints "Number::output() not defined." Complex c; c.output(cout); // prints "Hello from Complex::output()." Number & nr = c; nr.output(cout); // prints "Hello from Complex::output()." }
int main() { Number n; n.output(cout); // prints "Number::output() not defined." Complex c; c.output(cout); // prints "Hello from Complex::output()." n = c; // c is chopped to fit n. n.output(cout); // prints "Number::output() not defined." }
Number::~Number
is not virtual, static-type look-up is used -
Complex::~Complex
is never called.
$ cat t.cc #includeusing std::cerr; using std::cout; struct Number { virtual void output(ostream &); }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Complex c; c.output(cout); // prints "Hello from Complex::output()." } $ g++ -o t t.cc /var/tmp/ccSKs5j4.o(.gnu.linkonce.d._vt.7Complex+0xc): undefined reference to Number::output(ostream &) /var/tmp/ccSKs5j4.o: In function Complex type_info function: /var/tmp/ccSKs5j4.o(.gnu.linkonce.t.__tf7Complex+0x1c): undefined reference to Number type_info function /var/tmp/ccSKs5j4.o(.gnu.linkonce.t.__tf7Complex+0x34): undefined reference to Number type_info node /var/tmp/ccSKs5j4.o(.gnu.linkonce.t.__tf7Complex+0x38): undefined reference to Number type_info node /var/tmp/ccSKs5j4.o: In function Number::Number(void): /var/tmp/ccSKs5j4.o(.Number::gnu.linkonce.t.(void)+0x8): undefined reference to Number virtual table /var/tmp/ccSKs5j4.o(.Number::gnu.linkonce.t.(void)+0xc): 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(std::basic_ostream >&). 1 Warning(s) detected. $
struct Number { virtual void output(ostream &) { cerr << "Trying to call Number::output().\n"; abort(); } };
struct Number { virtual void output(ostream &) = 0; };
$ cat t.cc #includeusing std::ostream; struct Number { virtual void output(ostream &) = 0; }; int main() { Number n; } $ g++ -c t.cc t.cc: In function int main(): t.cc:12: cannot declare variable n to be of type Number t.cc:12: since the following virtual functions are abstract: t.cc:8: void Number::output(ostream &) $ CC -c t.cc "t.cc", line 12: Error: Cannot create a variable for abstract class Number. 1 Error(s) detected. $
struct Number { virtual void output(ostream &) const = 0; }; struct Complex : Number { void output(ostream &) const { cout << "Hello from Complex::output().\n"; } }; int main() { Complex c; Number & nr = c; Number * np = &c; nr.output(cout); // Prints "Hello from Complex::output()." np->output(cout); // Prints "Hello from Complex::output()." }
abstract
behaves like virtual
- a child function is
abstract unless its defined; no need to use abstract
again in
the child
$ cat t.cc #includeusing std::cerr; using std::ostream; struct Number { virtual void output(ostream &) const = 0; }; struct Complex : Number { // output() is still abstract virtual. }; int main() { Complex c; Number & nr = c; Number * np = &c; nr.output(cout); // Prints "Hello from Complex::output()." np->output(cout); // Prints "Hello from Complex::output()." } $ g++ -c t.cc t.cc: In function int main(): t.cc:15: cannot declare variable c to be of type Complex t.cc:15: since the following virtual functions are abstract: t.cc:7: void Number::output(ostream &) const $
struct A { virtual void hi(unsigned) { cout << "Hello from A:hi().\n"; } virtual void bye(int) { cout << "Bye from A:hi().\n"; } }; struct B : A { void hi(int) { cout << "Hi from B:hi().\n"; } void bye(int) { cout << "Bye from B:bye().\n"; } }; int main() { B b; A * ap = &b; ap->hi(0); // an int isn't an unsigned; prints "Hello from A:hi()." ap->bye(0); // prints "Bye from B:bye()." }
const
function modifier takes part too
struct A { virtual void hi(void) { cout << "Hello from A:hi().\n"; } virtual void bye(void) const { cout << "Bye from A:bye().\n"; } }; struct B : A { void hi(void) const { cout << "Hi from B:hi().\n"; } void bye(void) const { cout << "Bye from B:bye().\n"; } }; int main() { B b; A * ap = &b; ap->hi(); // hi() const isn't hi(); prints "Hello from A:hi()." ap->bye(); // prints "Bye from B:bye()." }
This page last modified on 22 April 2002.