定义:
共有、私有、保护派生指的是基类中pulic和protected成员以什么形式出现子啊派生类中
知识查漏补缺:
派生类如若出现与父类同名的话 构造函数不能直接赋值否则会出现冲突
使用构造函数时,直接用父辈的就行
#include<bits/stdc++.h>
using namespace std;
class TableTennisPlayer{
private:
string firstname;
string lastname;
bool hasTable;
public:
TableTennisPlayer( string a, string b, bool f){
hasTable=f;
firstname=a;
lastname=b;
};
string FirstName() const{
return firstname;
}
string LastName() const{
return lastname;}
bool HasTable() const{return hasTable;
}
};
class RatedPlayer:public TableTennisPlayer{
private:
int rating;
public:
int Rating();
RatedPlayer(int a,const string &b,const string &c,bool d):TableTennisPlayer(b,c,d),rating(a){
}
};
int RatedPlayer::Rating(){
return rating;
}
int main(){
string firstname, lastname;
bool hasTable;
int rating;
char flag;
while(cin>>flag){
if(flag=='T'){
cin>>firstname>>lastname>>hasTable;
TableTennisPlayer tp(firstname,lastname,hasTable);
if(tp.HasTable())
cout<<tp.FirstName()<<" "<<tp.LastName()<<" has a table.\n";
else
cout<<tp.FirstName()<<" "<<tp.LastName()<<" hasn't a table.\n";
} else if(flag=='R'){
cin>>firstname>>lastname>>hasTable>>rating;
RatedPlayer rp(rating,firstname,lastname,hasTable);
if(rp.HasTable())
cout<<rp.FirstName()<<" "<<rp.LastName()<<" has a table. The rating is "<<rp.Rating()<<".\n";
else
cout<<rp.FirstName()<<" "<<rp.LastName()<<" hasn't a table. The rating is "<<rp.Rating()<<".\n";
}
}
return 0;
}
再者,虚构函数如果提前出现把指针的内存空间删了的话 后续其他派生类就无法调用虚构函数了
这里着重复习一下派生类虚构函数:
派生类析构函数
关于为什么需要虚析构函数:
在C++中,虚析构函数非常重要,尤其是当涉及到使用多态和基类指针或引用时。下面是几个使用虚析构函数的理由,以及为什么直接写析构函数可能不足以处理所有情况:
1. **保证合适的析构顺序**:当你通过指向派生类的基类指针来删除对象时,如果没有定义虚析构函数,那么调用`delete`操作符可能会只析构基类部分而忽略派生类部分。这意味着派生类的资源不会被释放,从而导致内存泄漏。
2. **避免强制类型转换问题**:如果你有一个类型为基类的指针,但实际上指向派生类的对象,又由于基类的析构函数不是虚的,那么当它指向派生类时被删除,基类的析构函数会被调用来析构派生类的对象。这可能导致运行时错误。
3. **支持多态行为**:当你创建一个指向多态对象的基类指针并且想要删除这个对象时,虚析构函数可以确保按照继承层次由内到外依次调用析构函数,释放所有级别的资源。
4. **维持一定的设计准则**:在C++中,通常建议如果有虚函数(表明类涉及到多态),就应该将析构函数声明为虚函数。这是一种编程风格,可以保持代码的一致性,并帮助其他开发者理解你的类设计意图。
5. **接口的抽象性**:当类被设计为抽象基类时(也就是说,它包含纯虚函数),将析构函数声明为虚的允许派生类正确地析构,特别是在使用多态时。
6. **安全的向下转型**:如果基类的析构函数是虚的,安全性更高的向下转型(向下推理派生类,然后使用相匹配的析构函数)将变得可能。
因此,除非类明确地不被设计为基类(也就是说,你肯定没有人会从这个类派生新的子类),并且类没有虚函数,否则在实践中通常会将析构函数声明为虚函数。这样可以保证无论对象是通过基类指针或引用删除,都能确保调用正确的析构函数来准确和安全地清理资源。
纯虚函数:
纯虚函数是C++中的一个抽象概念,它们在抽象类(也被称为接口或基类)中定义。一个纯虚函数是没有任何实现的虚函数,其目的是强迫派生类提供自己的实现方式。
纯虚函数的定义:
纯虚函数在声明时使用= 0
来指示没有函数体。例如:
cpp复制代码
class Interface { public: virtual void pureVirtualFunction() = 0; };
特性和作用:
-
强制派生类实现:如果一个类包含至少一个纯虚拟函数,那么这个类就成为了抽象类,它不能被实例化。这意味着任何派生此类的子类必须实现所有的纯虚拟函数。这确保了子类对某些基础行为有自己的定义。
-
定义接口:纯虚拟函数用于定义一组相关功能的接口。不同的派生类可以根据自己的需求实现这个接口,从而实现多态性。
-
增强代码的灵活性:它们允许设计灵活的框架,使得你的代码不是刚性的,可以适应不同类型的对象行为。
-
促进良好的OOP实践:纯虚拟函数强制子类遵循接口规范,即它们必须提供特定行为的具体实现。
应用:
纯虚拟函数的应用场景非常广泛,以下是一些常见的应用案例:
-
接口规范:在一个由多种类型对象组成的系统(例如动物或车辆)中,如果不同的对象类型将表现出不同的行为,则可以使用接口规范来确保所有对象都有某些可预测的行为。
-
自动派生类生成逻辑:当需要让不同的子类在接收到某个触发条件时执行不同的逻辑时,纯虚拟函数非常适合。通过在基类中定义一个纯虚拟函数,并在子类中进行重写,可以实现特定的自动逻辑。
-
使用多态提供灵活性:在允许多种类型的对象共享相同类型的操作的情况下,可以将行为抽象化,并使用纯虚拟函数来定义这些行为。
-
设计模式中的实现:在某些设计模式中,可能会使用纯虚拟函数来实现特定的行为。例如,工厂方法模式中,工厂类就是一个抽象类,包含一个纯虚拟的创建对象的方法
#include <iostream>
#include <cmath>
using namespace std;
const double PI = acos(-1.0);
class Shape{
public:
virtual double area() = 0;
};
class Circle : public Shape{
private:
double r;
public:
Circle(double r) :r(r){}
double area(){ return PI*r*r; }
};
class rightTriangle : public Shape{
private:
double x, y;
public:
rightTriangle(double x, double y): x(x),y(y){}
double area(){return (x*y)/2;}
};
class Rectangle : public Shape {
private:
double length;
double width;
public:
Rectangle(double x, double y) : length(x), width(y){}
double area(){ return width*length; }
};
int main()
{
Circle c(3);
rightTriangle t(3,4);
Rectangle r(5, 4);
Shape * p;
p = &c;
cout<<p->area()<<endl;
p = &t;
cout<<p->area()<<endl;
p = &r;
cout << p->area() << endl;
p = NULL;
return 0;
}