重载是什么: 函数重载是函数的一种特殊情况,c++允许在同一作用域中声明几个功能类似的同名函数,这些函数的形参列表(参数个数或类型或顺序)必须不同,对返回值不做要求,因为无法通过改变参数列表来判断调用的是那一个重载函数。 注意点: 1.函数重载在同一作用域 2.函数重载与返回值无关 3.类静态成员函数可以和普通成员函数构成重载
int add(int a,int b) { return a+b; } double add(double a,double b)//返回值,参数类型不同 { return a+b; } int add(int a,int b,int c)//参数个数不同 { return a+b+c; }那c++是如何支持重载的呢? 我们通过linux演示c++如何支持的函数重载,因为Linux下gcc的修饰规则比较容易理解
int Add(int a,int b) { return a+b; } void func(int a,double b,int *p) {} int main() { Add(1,2); func(1,2,0); return 0; }对于上面的代码,先采用c编译器编译,我们会发现函数名字的修饰没有发生变化,依旧是函数名称 接下来我们再使用C++编译器编译,会发现函数名称发生了变化,编译器将函数的参数类型添加到了修改之后的名称后面 所以C++支持函数重载的原因是:C++可以通过函数的修饰规则区分,不同的参数,经过规则修饰之后的名字也不同。
什么是覆盖:覆盖也叫做重写,指的是子类与父类中返回值类型,参数,名称均相同的虚函数,此时构成虚函数的覆盖(覆盖是原理层的叫 法,在语法上叫做重写)
class A { public: virtual void func() { cout << "A" << endl; } }; class B : public A { public: virtual void func() { cout << "B" << endl; } }; void func(A &temp) { temp.func(); } int main() { A t1; func(t1); //A B t2; func(t2); //B }覆盖存在两种例外情况 1.协变:当子类重写父类虚函数时,子类中重写的函数的返回的指针或引用是父类中被重写函数的返回的指针或引用的子类型**
class A{}; class B : public A {}; class Person { public: virtual A* f() { return new A; } }; class Student : public Person { public: virtual B* f() { return new B; } };2.析构函数的重写:若父类的析构函数是虚函数,则此时子类的析构函数只要定义,无论有没有virtual关键字修饰,都与父类的析构函数构成重载 此时编译器对析构函数的名称处理成了destructor
class A { public: virtual void ~A() { cout<<"~A"<<endl; } }; class B { public: virtual ~B() { cout<<"~B"<<endl; } }; int main() { A* a = new A; B* b = new B; //只有子类对父类的析构函数进行重写,才会保证对象析构时,会正确调用各自的析构函数 delete a; delete b; }C++提供了override和final关键字可以帮助用户检查是否重写 1.override:检查子类虚函数是否已经重写了父类的某个虚函数,若没有完成重写则报错
class A { public: virtual void func_1() {} }; class B : public A { public: virtual void func_1() override { cout << "func_2" << endl; } };2.final: 修饰虚函数,表示该虚函数不能再被继承,也可以修饰类,使类不能被继承
class A { public: virtual void func() final {} }; class final B : public A { public: //virtual void func(){} }; class C : public B //报错,无法重写 { public: void func_1() {} };什么是隐藏: 当子类和父类中含有同名函数,此时子类成员将屏蔽父类对同名成员的直接访问,这种情况叫做隐藏。隐藏对函数参数和返回值不做要求,只需要名称相同就可以 子类是如何屏蔽父类中的同名函数呢? 当我们调用一个类的成员函数时,编译器会沿着类的继承顺序一级一级的向上查找函数的定义,如果找到了就停止查找。所以当子类和父类中都有一个名字相同的函数,那么编译器最终选择的是子类中的函数,而不是父类中的,也可以说是阻止了编译器向上查找。
class A { public: int num_1 = 1; void func() { cout<<"func()"<<endl; } }; class B : public A { public: int num_1 = 10; //与父类A中的同名成员num_1构成隐藏 void func(int i) { cout<<"num_1 = "<<A::num_1<<endl; // 1 cout<<"num_1 = "<<num_1<<endl;// 10 A::func(); //在子类中访问可以使用 "父类::父类成员" 显式访问 cout<<"func(int i):"<<i<<endl;//与父类中func函数名相同构成隐藏 } }; int main() { B t; t.func(10); }1.函数重载发生在同一作用域 2.函数覆盖,隐藏发生在不同作用域(分别在父类和子类中) 3.覆盖是隐藏的一种特殊情况 4,构成覆盖的函数名,参数,返回值都相同(协变除外) 5.重写的两个函数必须为虚函数
