鹤岗哈尔滨网站建设,专门做电容的网站,网站开发语言哪种好,wordpress采集别人公众号C 中的继承和多态 一、继承二、函数重载、隐藏、覆盖、重写1.函数重载#xff08;Function Overload#xff09;2.函数隐藏#xff08;Function Hiding#xff09;3.函数重写与函数覆盖#xff08;Function Override#xff09; 三、多态四、纯虚函数和抽象类五、多重继承… C 中的继承和多态 一、继承二、函数重载、隐藏、覆盖、重写1.函数重载Function Overload2.函数隐藏Function Hiding3.函数重写与函数覆盖Function Override 三、多态四、纯虚函数和抽象类五、多重继承的二义性菱形继承 一、继承
继承允许我们依据一个类来定义另一个类这使得创建和维护一个应用程序变得更容易。这样做也达到了重用代码功能和提高执行效率的效果。
派生类的成员可以直接访问基类的保护成员protected但不能直接访问基类的私有成员private。
继承分为公有继承、保护继承与私有继承除了公有继承剩下两个很少用到三者区别如下 二、函数重载、隐藏、覆盖、重写
1.函数重载Function Overload
C规定在同一作用域中函数名相同但函数特征标即参数个数、类型、顺序不同时构成函数重载。
函数重载的注意事项
返回值类型不能作为重载的标准。参数是否为引用不能作为重载的标准尽管某些时候能通过编译但在调用时会产生二义性。成员函数是否被static修饰也不能作为重载的标准因为在通过实例化后的对象调用方法时无法区分是否要调用静态成员函数。一个函数不能既作为重载函数又作为有默认参数的函数因为当调用函数时如果少写一个参数系统无法判定是利用重载函数还是利用默认参数的函数即 int func(int a) 和 int func(int a 0) 是不能在同一作用域中同时存在的。
这里还要特别注意一下const修饰函数或函数参数时的情况
class A {
public:/*** 不管形参有没有const修饰实参都不会被修改二者在调用时没有区别因此不能构成重载*/void func(int a);void func(const int a); // NO/*** 由底层const修饰的指针指向的实参不能被修改二者在调用时存在区别因此可以构成重载*/void func_bot_p(int *a);void func_bot_p(const int *a); // YES/*** 不管有没有顶层const修饰该指针指向的内容都可以被修改二者在调用时没有区别因此不能构成重载*/void func_top_p(int *a);void func_top_p(int *const a); // NO/*** 在const修饰引用时实参不能被修改二者在调用时存在区别因此可以构成重载*/void func_ref(int a);void func_ref(const int a); // YES/*** 由const修饰的成员函数只能由const对象调用二者在调用时存在区别因此可以构成重载*/void func_ret(int a);void func_ret(int a) const; // YES
};2.函数隐藏Function Hiding
不同作用域中定义的同名函数会构成函数隐藏不要求函数返回值和函数参数类型相同。
类成员函数会屏蔽全局函数派生类成员函数会屏蔽与其同名的基类成员函数但如果该基类成员函数为虚函数且函数返回值和特征标相同则构成函数重写。
#include iostreamusing namespace std;void func() {cout global::func() endl;
}class A {
public:/*** 隐藏了外部的func*/void func() {cout A::func() endl;}void use_func() {func();::func(); // 使用全局函数时要加作用域}
};class B : public A {
public:/*** 隐藏了基类的func*/void func() {cout B::func() endl;}void use_func() {func();A::func(); // 使用基类函数时要加作用域}
};int main() {A a;B b;a.use_func();b.use_func();
}atreusMacBook-Pro % g main.cpp -o main -stdc11
atreusMacBook-Pro % ./main
A::func()
global::func()
B::func()
A::func()
atreusMacBook-Pro % 3.函数重写与函数覆盖Function Override
派生类中与基类同返回值类型、同名和同特征标的虚函数重定义构成虚函数覆盖也叫虚函数重写。
需要注意的是在默认情况下如果重新定义了继承的方法应确保与原来的原型完全相同但如果返回类型是基类引用或指针则可以修改为指向派生类的引用或指针这种新出现的特性叫做返回类型协变covariance of return type。
#include iostreamusing namespace std;class A {
public:void func() {cout A::func() endl;}virtual void func_v() {cout A::func_v() endl;}
};class B : public A {
public:/* 函数隐藏 */void func() {cout B::func() endl;}/* 函数重载 */void func_v() override {cout B::func_v() endl;}
};int main() {A *a new B;a-func();a-func_v();delete a;
}atreusMacBook-Pro % g main.cpp -o main -stdc11
atreusMacBook-Pro % ./main
A::func()
B::func_v()
atreusMacBook-Pro % 三、多态
多态是指一个方法同时具有多种形态具体形态取决于调用该方法的具体对象。从实现的角度可以将多态分为编译时多态主要通过函数模板、函数重载和运算符重载实现和运行时多态主要通过虚函数和函数重写实现。
对于运行时多态其实现主要有三个前提
存在继承。存在函数重写覆盖。存在基类指针或者引用指向子类对象。
运行时多态的实现要借助于动态绑定动态绑定借助于虚函数实现虚函数的限制如下
只有类的成员函数才能声明为虚函数。基类的析构函数可以是虚函数且通常声明为虚函数。构造函数不能为虚函数。内联函数不能是虚函数。静态成员函数不能是虚函数。
虚函数、虚函数表及虚函数实现多态的原理
其中动态绑定是运行时绑定通过地址实现它是指基类的指针或引用有可能指向不同的派生类对象。对于非虚函数执行时实际调用该函数的对象类型即为该指针或引用的静态类型。而对于虚函数执行时实际调用该函数的对象类型为该指针或引用所指对象的实际类型。 四、纯虚函数和抽象类
当类声明中包含纯虚函数定义是末尾有 0 的虚函数时则不能创建该类的对象这个类变为抽象类C中的抽象类类似于Java中的接口抽象类必须至少包含一个纯虚函数。
此外对于抽象类还有以下注意事项
抽象类只能用作其他类的基类当然也可以作为另一个抽象类的基类。抽象类不能用来定义对象不能实例化也不能用作参数类型、函数返回类型或显式转换的类型。如果一个非抽象类从抽象类中派生则其必须通过覆盖来实现所有的继承而来的抽象成员函数。
#include iostream/* 抽象类 */
class Car {
public:virtual void showName() 0; // 纯虚函数
};class Audi : public Car {
public:void showName() override { std::cout Audi std::endl; }
};class Volvo : public Car {
public:void showName() override { std::cout Volvo std::endl; }
};int main() {Audi audi;Volvo volvo;audi.showName(); // Audivolvo.showName(); // Volvoreturn 0;
}五、多重继承的二义性菱形继承
菱形继承是指当类B和类C同时继承于基类A类D同时继承于类B和类C此时类A中的成员变量和成员函数继承到类D中就变成了两份在D中调用A中的成员会导致二义性同时一个变量分两份存储也存在内存空间浪费的问题。 通过虚基类和虚继承机制可以在多继承中只保留一份共同成员从而解决了多继承导致的命名冲突和数据冗余。
在继承方式前面加上 virtual 关键字就是虚继承如果不采用虚继承在类D中使用类A中的m_a时则需要通过 B::m_a 或 C::m_a 来指定具体使用哪个m_a。
#include iostreamusing namespace std;class A {
protected:int m_a 0;
};class B : virtual public A {
protected:int m_b 1;
};class C : virtual public A {
protected:int m_c 2;
};class D : public B, public C {
protected:int m_d 3;public:D() {cout m_a endl;cout m_b endl;cout m_c endl;cout m_d endl;}
};int main() {D d;return 0;
}atreusMacBook-Pro % g main.cpp -o main -stdc11
atreusMacBook-Pro % ./main
0
1
2
3
atreusMacBook-Pro % C标准库中的iostream类就是一个虚继承的实际应用案例。iostream从istream和ostream直接继承而来而istream和ostream又都继承自一个共同的名为base_ios的类是典型的菱形继承。 参考
https://cloud.tencent.com/developer/article/1177174 https://blog.csdn.net/weixin_39640298/article/details/88725073 http://c.biancheng.net/view/2280.html