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.