默认情形下,成员函数的解析都是编译时静态进行。如果要让成员函数的解析在程序运行时动态进行,需要在成员函数的声明前加上关键字virtual:
cpp
//LibMat声明表示,其析构函数和print()函数皆为虚函数
class LibMat{
public:
LibMat()
{
cout<<"LibMat::LibMat() default constructor!\m";
}
virtual ~LibMat()
{
cout<<"LibMat::~LibMat() destructor!\n";
}
virtual void print()const
{
cout<<"LibMat::print()--I am a LibMat object!\n";
}
};
虚函数的作用:
用基类的指针指向不同的派生类的对象时,基类指针调用其虚成员函数,会调用真正指向对象的成员函数 ,而不是基类中定义的成员函数;若不是虚函数,则只会调用基类中定义的那个函数。
cpp
void print(const LibMat &mat)
{
cout<<"in global print():about to print mat.print()\n";
//下一行会依据mat实际指向的对象
//解析该执行哪一个print()成员函数
mat.print();
}
cpp
//main函数中重复调用print()
//并依次将三个对象作为参数传递给它
//每次执行
int main()
{
cout<<"\n"<<"Creating a LibMat object to print()\n";
LibMat libmat;
print(libmat);
cout<<"\n"<<"Creating a Book object to print()\n";
Book b("The Castle","Franz Kafka");
print(b);
cout<<"\n"<<"Creating an AudiBook = object to print()\n";
AudioBook ab("Man without Qualities","Robert Musil","Kenneth Meyer");
print(ab);
}
cpp
class Book : public LibMat { //定义派生类Book,继承自LibMat
public:
Book( const string &title, const string &author )
: _title( title ), _author( author ){
cout << "Book::Book( " << _title
<< ", " << _author << " ) constructor\n";
}
~Book(){
cout << "Book::~Book() destructor!\n";
}
virtual void print() const {
cout << "Book::print() -- I am a Book object!\n"
<< "My title is: " << _title << '\n'
<< "My author is: " << _author << endl;
}
const string& title() const { return _title; }
const string& author() const { return _author; }
protected:
string _title;
string _author;
};
被声明为protected的所有成员都可以被派生类直接访问;除了派生类之外,都不得直接访问protected成员。
cpp
class AudioBook : public Book {
public:
AudioBook( const string &title,
const string &author,
const string &narrator )
: Book( title, author ), _narrator( narrator )
{
cout << "AudioBook::AudioBook( " << _title
<< ", " << _author
<< ", " << _narrator
<< " ) constructor\n";
}
~AudioBook(){
cout << "AudioBook::~AudioBook() destructor!\n";
}
virtual void print() const {
cout << "AudioBook::print() -- I am a AudioBook object!\n"
<< "My title is: " << _title << '\n'
<< "My author is: " << _author << '\n'
<< "My narrator is: " << _narrator << endl;
}
const string& narrator() const { return _narrator; }
protected:
string _narrator;
};
派生类的构造函数作用后顺序:
基类的构造函数、派生类的析构函数、基类的析构函数。
总结
示例中分别实现了三种类:LibMat
,Book
,AudioBook
,
- 三者的成员函数有重合之处,其中
print()
这一成员函数的具体实现各有不同,使用virtual
关键字,以调用真正指向的对象的成员函数(虚拟调用); - 使用
:
号和public
实现派生类继承的标记,不必刻意区分"继承而来的成员"和"自身定义的成员",在其使用上无特别的不同之处; - 被声明为
protected
的所有成员都可以被派生类直接访问;
除了派生类之外,都不得直接访问protected成员。 - 当程序定义出一个派生对象,基类和派生类的构造函数 都会被执行;
当派生对象被销毁时,基类和派生类的析构函数 也都会被执行,且执行顺序颠倒。