一、概念
面向对象是数据抽象、继承、动态绑定。
数据抽象,可以实现类接口与实现分离;
继承,派生类可以继承基类;
动态绑定,由于存在派生类和基类的继承函数,在实际运行时,会根据传递的实参选择函数的版本,以此实现运行时绑定。
1.基类
基类中通常应该定义一个虚析构函数。
虚函数:派生类可以通过其成员函数覆盖基类的函数。
基类中定义了静态成员,则整个继承体系只存在该成员的唯一定义。
class base {
public:
base() = default;
virtual ~base() = default;
virtual void print() {
std::cout << "This is base!" << std::endl;
}
static void hello() { std::cout << "hello!" << std::endl;}
};
2.派生类
派生类继承基类
派生类中函数覆盖了基类中的函数时,可以使用virtual说明也可以不用。
class Derived:public base {
Derived() = default;
void print () {
std::cout << "This id Derived!" << std::endl;
};
3.final 和override说明符
final 关键字加在函数后面,显示的表示不允许其他类覆盖此函数;
ovriride 关键字加在派生类函数后面,显示的说明该函数继承基类的虚函数,当派生类函数的形参没有和基类的一样时,会提示报错。
代码段 小部件
4.抽象基类和纯虚函数
基类中如果只定义函数接口,具体实现都在派生类中继承,则可以定义纯虚函数。
含有纯虚函数的基类称为抽象基类,抽象基类不可以直接创建,可以创建其派生类。
代码段 小部件
5.public protected private
public:没有限制的访问,外部成员也能访问;
protected:类自己的成员函数以及派生类的成员函数可以访问;
private:只有类自己成员函数可以访问。
class test_protest {
public:
void pub_men();
protected:
int prot_men;
private:
char priv_men;
};
class test_pri:test_protest {
public:
int f() {return prot_men;} // 可以访问protected成员
};
6.虚函数与作用域
若基类和派生类的实参不同,则无法通过基类的引用或者指针调用派生类的虚函数。
class base {
public:
virtual int fcn() {return 0;};
};
class D1:public base {
public:
int fcn(int) {return 1;};
virtual void f2() {std::cout << "D1->f2" << std::endl;};
};
class D2:public D1 {
public:
int fcn(int);
int fcn() {retrun 2;};
void f2() {std::cout << "D2->f2" << std::endl;};
};
int main(int argc, char** argv) {
base obj;
D1 d1obj;
D2 d2obj;
base *bp1 = &obj, *bp2 = &d1obj, *bp3 = &d2obj;
bp1->fcn(); //base::fcn
bp2->fcn(); //base::fcn
bp3->fcn(); //D2::fcn
D1 *d1p = &d1obj;
D2 *d2p = &d2obj;
d1p->f2();
d2p->f2();
};
7.虚析构函数
当delete一个动态分配的对象的指针时将执行析构函数。虚析构函数的虚属性也会被继承。派生类使用合成的析构函数还是自己的析构函数,都是虚函数,因此当delete基类的指针时将运行正确的析构函数。
如果基类的析构函数不是虚函数,则delete一个指向派生类对象的基类指针将产生未定义行为。
当类中没有定义析构函数时,编译器会生成一个什么都不做的析构函数,默认生成的析构函数是普通的析构函数不是虚函数。所以基类要显示的定义虚析构函数。
class base {
public:
virtual ~base = default;
virtual int fcn() {return 0;};
};
class D1:public base {
public:
~base = default;
int fcn(int) {return 1;};
virtual void f2() {std::cout << "D1->f2" << std::endl;};
};
int main (int argc, char** argv) {
base *bp = new base; //静态与动态一致
delete bp; //调用base的析构函数
bp = new D1; //静态类型与动态类型不一致
delete bp; //调用D1的析构函数
return 0;
}