C++继承和派生笔记

继承和派生

class Student:public Person

派生类把基类全部的成员(不包括构造函数和解析函数)继承下来

公有继承

基类成员继承给派生类后,其访问权限不变,但基类成员的私有成员在派生类中不可以直接访问

私有继承

基类中的所有成员都以私有成员身份出现在派生类中,基类的私有成员在派生类中不可直接访问

保护成员和保护继承

从用户的角度来看,保护成员等价于私有成员,但是有一点不同,保护成员可以被派生类的成员函数使用

在保护继承中,基类的公有和保护成员都以保护成员的身份出现在派生类中,而基类的私有成员不可以直接访问

派生类的构造函数
class Person
{
public:
	Person()
	{
		id = 1;
		name = "";
		sex = 'L';
	}
    Person(int id,string name,char sex)
    {
        this->id = id;
        this->name = name;
        this->sex = sex;
    }
private:
    int id;
    string name;
    char sex;
};

class Student:public Person
{	
	// 在派生类构造函数的形参列表中,要给出初始化基类和派生类的数据成员所需要的全部参数	
	Student(int id,string name,char sex,float score):Person(id,name,sex)
	{
		this->score = score;
	}
private
	float score;
};

当创建一个派生类的对象时,系统首先自动调用基类构造函数,再调用派生类的构造函数。

如果一个类只作为基类使用,一般不会用于实例化对象,就会把这个基数的数据成员和构造函数设置为protected访问权限,这样既保证了数据的封装性,又能在派生类中访问,保证了数据的一致性。

派生类的析构函数

先执行派生类的析构函数,然后调用基类的析构函数。

多继承
#include<iostream>
using namespace std;
class A
{
public:
    A(int x)
    {
        this->x = x;
    }
private:
    int x;
    
};
class B
{
public:
    B(int y)
    {
        this->y = y;
    }
private:
    int y;
};

class C:public A,public B
{
public:
	C(int x,int y,int z):A(x),B(y)
	{
		this->z = z;
	}
private:
	 int z;
    
}
    

同名函数的屏蔽:

如果派生类和基类的函数同名,但是参数不同,此时,无论有没有virtual关键字,基类函数被隐藏。

如果函数同名,参数相同,并且无virtual关键字,基类函数被隐藏。(注意和函数重写的区别)

采用:“对象名.基类名::成员名”唯一访问函数

多继承的时候可能会产生二义性问题。c++提供虚基类的方法,当基类通过多个路径被一个派生类继承时,该派生类只继承该基类一次。

class A:virtual public M

类的组合

继承时纵向的,组合是横向的。

#include<iostream>
using namespace std;
class Point
{
    
public:
    Point():x(0),y(0)
    {
        cout<<"Point's default constructor was called"<<endl;
    }
    Point(double x,double y):x(x),y(y)
    {
        cout<<"Point's constructor was called"<<endl;
    }
    Point(Point &p)
    {
        x = p.x;
        y = p.y;
        cout<<"Point's copyConstructor was called"<<endl;
    }
private:
    double x;
    double y;
};

class Line
{
public:
	Line():A(),B()
    {}
    
    Line(double x1,double y1,double x2,double y2):A(x1,y1),B(x2,y2)
    {}
    
    Line(Point p1,Point p2):A(p1),B(p2)
    {}
Private:
    Point A;
    Point B;
};
基类和派生类的转换

不能把一个整形数据赋值给指针变量

可以用派生类对象对基类对象进行赋值,并且具有赋值兼容性(公有继承)

多态性与虚函数

虚函数

满足的条件:

  • 基类与子类之间为公有继承方式
  • 基类函数要声明为虚函数
  • 通过基类指针或者引用来调用函数
class A
{
public:
	virtual void display
	{}
};
class B:public A
{
public:
	void display
	{}
}

void main()
{
	A *pa;
	B ba;
	pa = &ba;
	pa->display();
	// 虽然pa是A类的对象,但是执行的是B类的display()
}


在运行过程中,根据基类指针指向不同的派生类对象就可以访问响应对象的虚函数,从而实现了运行时的动态多态性。派生类的虚函数重写或者覆盖了基类的同名虚函数。

注意

  • virtual关键字只能出现在虚函数的原型声明中,在虚函数的实现中不能出现。
  • 将基类中的某一个成员声明为虚函数后,派生类中的同名函数(函数名相同,参数列表完全一样,返回值类型相同)自动成为虚函数。
  • 如果声明了某个成员函数为虚函数,则在该类中不能出现同名函数(函数名相同,参数列表完全一样,返回值类型相同),在以该类为基类的派生类中,也不能出现同名函数。
  • 非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数不能定义为虚函数,当可以将析构函数定义为虚函数。
  • 声明虚函数的时候,必须实现函数体。
  • 当通过基类指针删除指向子类的动态对象时,子类的析构函数没有被执行,说明子类对象动态分配的空间没有得到释放,造成了内存泄露。为解决这个问题,常常将基类的析构函数定义为虚函数。
纯虚函数
virtual void Area(); //错误,必须在基类中实现
virtual void Area()
{
}
//正确
virtual void Area() = 0;
//纯虚函数
抽象类

不用实例化对象,只作为一种“模板”用于派生的类,成为抽象类。

运算符重载

A operate+ (A &a1,A &a2)
{
	int x = a1.x + a2.x;
	A a(x);
	return a;

}
//定义一种新的加法算法

一般来说,重载函数中要用到一些private的变量,所以一般把重载函数定义为友元函数。

friend A operate+ (A &a1,A &a2);

有两个实例!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值