软文推广代理,seo推广怎么入门,人人建站网,安卓app快速开发个人主页点击直达#xff1a;小白不是程序媛
C系列专栏#xff1a;C干货铺
代码仓库#xff1a;Gitee 目录
多态的概念
多态的定义和实现
多态的定义条件
虚函数
虚函数的重写
特殊情况
协变#xff08;基类和派生类的虚函数返回值不同#xff09;
析构函数的重…
个人主页点击直达小白不是程序媛
C系列专栏C干货铺
代码仓库Gitee 目录
多态的概念
多态的定义和实现
多态的定义条件
虚函数
虚函数的重写
特殊情况
协变基类和派生类的虚函数返回值不同
析构函数的重写
C11 override 和 final关键字
重载、重写覆盖、重定义隐藏的对比
抽象类 多态的概念 多态的概念通俗来说就是多种形态具体点就是去完成某个行为当不同的对象去完成时会产生出不同的状态。 举个栗子很多朋友在外地上大学回家或者去学校可能都会买火车票或者其他交通工具的票。但是作为一个大学生我们是有学生认证的大学生身份买票有打折优惠但是对于其他不是学生的公民来说就是普通人的身份是享受不到这个优惠的必须全价买票又或者对于军人来说他们有军人的身份军人优先买票。 因此对于买票这个行为当普通人买票时是全价买票学生买票时是半价买票军人 买票时是优先买票。 多态的定义和实现
多态的定义条件
多态是在不同继承关系的类对象去调用同一函数产生了不同的行为。比如Student继承了 Person。Person对象买票全价Student对象买票半价。
那么在继承中要构成多态还有两个条件 必须通过基类的指针或者引用调用虚函数被调用的函数必须是虚函数且派生类必须对基类的虚函数进行重写 虚函数 虚函数即被virtual修饰的类成员函数称为虚函数。 class Person {
public:virtual void Buy() { cout 买票-全价 endl;}
};
虚函数的重写 虚函数的重写(覆盖)派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型、函数名字、参数列表完全相同)称子类的虚函数重写了基类的虚函数。 注意重写只是对函数体的内容重写而不是对整个函数重写使用的还是基类的接口只不过是函数体的内容变了。
class Person
{
public :virtual void Buy(){cout 普通人——全价买票 endl;}
};
class Student :public Person
{
public:virtual void Buy(){cout 学生——半价买票 endl;}
};
void Func(Person p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
} 特殊情况
在重写基类虚函数时派生类的虚函数在不加virtual关键字时虽然也可以构成重写(因为继承后基类的虚函数被继承下来了在派生类依旧保持虚函数属性),但是该种写法不是很规范不建议这样使用。
class Person
{
public :virtual void Buy(){cout 普通人——全价买票 endl;}
};
class Student :public Person
{
public:virtual void Buy(){cout 学生——半价票 endl;}//派生类的虚函数前面可以不加virtual 但是这样并不规范不建议这样使用//void Buy()//{// cout 学生——半价票 endl;//}
};
void Func(Person p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}虚函数的两个例外
协变基类和派生类的虚函数返回值不同 派生类重写基类虚函数时与基类虚函数返回值类型不同。即基类虚函数返回基类对象的指 针或者引用派生类虚函数返回派生类对象的指针或者引用时称为协变。 class Person
{
public:virtual Person* Buy(){cout 普通人——全价买票 endl;return nullptr;}
};
class Student :public Person
{
public:virtual Student* Buy(){cout 学生——半价票 endl;return nullptr;}
};
void Func(Person p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
}返回值可以为其他类的指针
class A
{
public:
};
class B : public A
{
public:
};
class Person
{
public:virtual A* Buy(){cout 普通人——全价买票 endl;return nullptr;}
};
class Student :public Person
{
public:virtual B* Buy(){cout 学生——半价票 endl;return nullptr;}
};
void Func(Person p)
{p.Buy();
}
int main()
{Person p1;Student s1;Func(p1);Func(s1);return 0;
} 析构函数的重写 如果基类的析构函数为虚函数此时派生类析构函数只要定义无论是否加virtual关键字 都与基类的析构函数构成重写虽然基类与派生类析构函数名字不同。虽然函数名不相同 看起来违背了重写的规则其实不然这里可以理解为编译器对析构函数的名称做了特殊处 理编译后析构函数的名称统一处理成destructor。 class Person
{
public :virtual ~Person(){cout ~Person() endl;}
};
class Student
{
public:virtual ~Student(){cout ~Student() endl;}
};
//只有派生类Student的析构函数重写了Person的析构函数下面的delete对象调用析构函
数才能构成多态才能保证p1和p2指向的对象正确的调用析构函数。
int main()
{Person* p1 new Person;Person* p2 new Student;delete p1;delete p2;
} C11 override 和 final关键字
从上面可以看出C对函数重写的要求比较严格但是有些情况下由于疏忽可能会导致函数 名字母次序写反而无法构成重载而这种错误在编译期间是不会报出的只有在程序运行时没有 得到预期结果才来debug会得不偿失因此C11提供了override和final两个关键字可以帮 助用户检测是否重写。 final修饰虚函数表示该虚函数不能再被重写 class Person
{
public :virtual void Func()final{cout 被final修饰 endl;}
};
class Student : public Person
{
public:virtual void Func(){}
};override: 检查派生类虚函数是否重写了基类某个虚函数如果没有重写编译报错。 //override
// 检查派生类虚函数是否重写了基类某个虚函数如果没有重写编译报错。
class Person
{
public:virtual void Func() {};
};
class Student : public Person
{
public:void Func ()override {};
}; 重载、重写覆盖、重定义隐藏的对比 抽象类
抽象类的概念 在虚函数的后面写上 0 则这个函数为纯虚函数。包含纯虚函数的类叫做抽象类也叫接口类抽象类不能实例化出对象。派生类继承后也不能实例化出对象只有重写纯虚函数派生类才能实例化出对象。纯虚函数规范了派生类必须重写另外纯虚函数更体现出了接口继承。 class car
{
public :virtual void Drive() 0;
};
class Benz :public car
{
public:virtual void Drive(){cout Benz-舒适 endl;}
};
class BMW :public car
{
public:virtual void Drive(){cout BMW-操控 endl;}
};
int main()
{Benz b;b.Drive();BMW m;m.Drive();return 0;
} 今天对继承之后的多态的分享到这就结束了希望大家读完后有很大的收获也可以在评论区点评文章中的内容和分享自己的看法。您三连的支持就是我前进的动力感谢大家的支持 !