一天接受两个挑战确实有点反应不过来。不过受到肯定说写博客是个好习惯,还是觉得有点小成就!继续坚持下去!等哪天回头来看自己已经能master那么多东西了就觉得真的在进步!
————————–>吐槽完毕。接下来是正文:
一、虚函数与纯虚函数
- 两者都在C++ OOP机制里面有着重要的作用,初学C++的时候没有仔细思考,现在回过头来总结发现其中还是有很多乐趣。通过用virtual关键词可以定义虚函数。
友元函数 构造函数 static静态函数 不能用virtual关键字修饰;
普通成员函数 和析构函数 可以用virtual关键字修饰;
虚函数的作用主要是当基类指针引用的是子类,则基类指针会调用子类同名的方法。下面展示下代码:
e.g 1
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "This is Base\n";
}
virtual void print()
{
cout << "This prints Base\n";
}
~Base()
{
cout << "Destory Base\n";
}
};
class Derived :public Base
{
public :
Derived()
{
cout << "This is Derived\n";
}
void print()
{
cout << "This prints Derived\n";
}
~Derived()
{
cout << "Destory Derived\n";
}
};
int main()
{
Derived *ptr_de=new Derived();
Base *ptr_base = ptr_de;
ptr_base->print();
delete ptr_de;
return 0;
}
输出结果:
This is Base
This is Derived
This prints Derived
Destory Derived
Destory Base
请按任意键继续…
2. 纯虚函数
请看代码:
class Base
{
public:
Base()
{
cout << "This is Base\n";
}
virtual void print() = 0;
~Base()
{
cout << "Destory Base\n";
}
};
class Derived : public Base
{
public :
Derived()
{
cout << "This is Derived\n";
}
void print()
{
cout << "This prints Derived\n";
}
~Derived()
{
cout << "Destory Derived\n";
}
};
纯虚函数,即基类并不定义函数的具体实现,而由基类去实现,如示例中
virtual void print() = 0; 则提供了一个类似JAVA的接口,但是由子类去实现。如果基类的函数都是这样的,那么这个基类也称为抽象类。一般来说,抽象类是不能进行实例化的。但有时还是能通过其它途径。
可以看以下文章:抽象基类不能被实例化?看我怎么破!
不过抽象类的提出正是为了深刻表示出OOP的优势,所以个人觉得抽象基类不能实例化还是有其设计理念在。因此不予以继续说明。
3. 虚继承
说了一点虚函数和纯虚函数,接下来说一个虚继承。啥是虚继承?
请看以下代码:
e.g2
#include<iostream>
using namespace std;
class GrandFather
{
public:
GrandFather() {}
void fun()
{
cout << "GrandFather call function!" << endl;
}
virtual ~GrandFather()
{
cout << "GrandFather destruction!" << endl;
}
};
class Father1 :virtual public GrandFather
{
public:
Father1() {}
void fun()
{
cout << "Father1 call function!" << endl;
}
};
class Father2 : virtual public GrandFather
{
public:
Father2() {}
};
class Son : public Father1, public Father2
{
public:
Son() {}
};
int main()
{
Son* son = new Son;
son->fun();
return 0;
}
运行结果是输出father1的fun函数,如果father2也有fun函数,则编译失败,因为不明确调用哪个fun.
如果father1 father2均没有fun,则会调用grand father的fun函数。
虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。
二、构造函数与析构函数
初始化对象时,会先调用函数的构造函数。销毁对象则会调用析构函数。那么经典的问题是,二者的顺序问题。
由e.g 1可知,->构造函数的顺序是:基类,派生类.而析构函数的顺序刚好反过来。<-
那么如果加了virtual变为虚函数呢。
请看e.g 3
#include<iostream>
using namespace std;
class Base
{
public:
Base()
{
cout << "This is Base\n";
}
virtual void print()
{
cout << "This prints Base\n";
}
virtual ~Base()
{
cout << "Destory Base\n";
}
};
class Derived : public Base
{
public :
Derived()
{
cout << "This is Derived\n";
}
void print()
{
cout << "This prints Derived\n";
}
~Derived()
{
cout << "Destory Derived\n";
}
};
int main()
{
Derived *ptr_de=new Derived();
Base *ptr_base = ptr_de;
ptr_base->print();
delete ptr_base; //这里与eg1比变化了,换做delete ptr_de的话效果也一样
return 0;
}
输出结果:
This is Base
This is Derived
This prints Derived
Destory Derived
Destory Base
请按任意键继续…
那么如果把e.g1 delete ptr_de改为delete ptr_base呢,则会发生只销毁了基类,而派生类没被销毁。
因为e.g1 delete ptr_base,只会从调用对应类的析构方法,没有执行derived的析构方法,而加上virtual了,则基类指针会先销毁子类,然后才是基类。
若有e.g2的虚继承,则会先创建虚基类,然后按照顺序创建派生类的构造函数,析构函数则刚好相反。
End: 先总结至此,后续再补充!