C++继承机制学习笔记

一、继承的作用

  • 代码的复用
  • 扩展功能
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 继承的作用1:代码的复用  2 扩展功能
class Father
{
public:
	void func1()
	{
		cout << "高颜值" << endl;
	}
	void func2()
	{
		cout << "有钱" << endl;
	}
};

class Son:public Father
{
public:
	void fun3()
	{
		cout << "油菜花" << endl;
	}
};

void test()
{
	Son s;
	s.func1();
	s.func2();
	s.fun3();
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

二、继承的方式

2.1 继承方式种类

  • 公有继承
  • 私有继承
  • 保护继承

2.2 子类从父类继承过来的成员的权限

2.2.1 公有继承
  • 公有成员:父类的公有属性成员进入子类还是公有
    类内和类外都可以访问私有成员
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:Father
{
public:
	void func()
	{
		cout << a <<endl;// 从类内进行访问 OK
	}
};

void test()
{
	Son1 s;
	s.a;// 从类外进行访问 OK
}

int main()
{
    test();

	return EXIT_SUCCESS;
}

  • 私有成员:父类的私有成员进入子类还是私有的成员

类内和类外都不可以访问私有成员

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:Father
{
public:
	void func()
	{
		//cout << a <<endl;// 从类内进行访问
		cout << b << endl;//私有成员不可以进行访问 报错
	}
};

void test()
{
	Son1 s;
	s.b;// 从类外进行访问私有成员 报错

}

int main()
{
	test();

	return EXIT_SUCCESS;
}
  • 保护成员:父类的成员到子类还是保护成员
    类内可以访问私有成员 类外不可以访问私有成员
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:Father
{
public:
	void func()
	{
		//cout << a <<endl;// 从类内进行访问
		cout << c << endl;//子类可以访问保护成员  不报错
	}
};

void test()
{
	Son1 s;
	s.b;// 从类外进行访问保护成员  报错
}

int main()
{
	test();
	return EXIT_SUCCESS;
}
2.2.2 保护继承
  • 公有属性

父类公有属性 子类保护属性

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};

class Son1:protected Father
{
public:
	void func()
	{
		cout << a <<endl;// 从类内进行访问 OK
	}
};

void test()
{
	Son1 s;
	s.a;// 从类外进行访问保护成员  报错
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

  • 私有属性

父类私有属性 子类还是私有属性

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:protected Father
{
public:
	void func()
	{
		cout << b <<endl;// 从类内进行访问 报错  仍然是私有属性
	}
};

void test() 
{
	Son1 s;
	s.b;// 从类外进行访问保护成员  报错  
}

int main()
{
	test();

	return EXIT_SUCCESS;
}

  • 保护属性
    父类保护属性 子类仍然是保护属性
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:protected Father
{
public:
	void func()
	{
		cout << c <<endl;// 从类内进行访问 OK
	}
};

void test() 
{
	Son1 s;
	s.c;// 从类外进行访问保护成员  报错  
}

int main()
{
	test();

	return EXIT_SUCCESS;
}
2.2.3 私有继承
  • 父类的公有属性成员 到子类是保护

  • 父类的私有属性成员 到子类还是私有

  • 父类的保护属性成员 到子类还是保护

  • 公有属性

公有属性变成保护属性

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:private Father
{
public:
	void func()
	{
		cout << a <<endl;// 从类内进行访问 OK
	}
};

void test() 
{
	Son1 s;
	s.a;// 从类外进行访问保护成员  报错    变成保护属性
}

int main()
{
	test();

	return EXIT_SUCCESS;
}

  • 私有属性
    父类的私有属性成员 到子类还是私有属性成员
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:private Father
{
public:
	void func()
	{
		cout << b <<endl;// 从类内进行访问 ERROR
	}
};

void test() 
{
	Son1 s;
	s.b;// 从类外进行访问保护成员  报错  还是私有属性
}

int main()
{
	test();

	return EXIT_SUCCESS;
}

  • 保护属性
    父类的保护属性 子类还是保护属性
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	int a;

private:
	int b;

protected:
	int c;
};


class Son1:private Father
{
public:
	void func()
	{
		cout << c <<endl;// 从类内进行访问 OK
	}
};

void test() 
{
	Son1 s;
	s.c;// 从类外进行访问保护成员  报错 还是保护属性
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

三、继承中的构造和析构的调用

  • 继承调用顺序
    先调用父类的构造函数 在调用子类的构造函数 析构函数调用顺序相反
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father() {
		cout << "构造函数" << endl;
	}

	~Father() {
		cout << "析构函数" << endl;
	}
};

// 先调用父类的构造函数 在调用子类的构造函数  析构函数调用顺序反之
class Son :public Father
{
public:
	Son() {
		cout << "Son构造函数" << endl;
	}

	~Son()
	{
		cout << "Son析构函数" << endl;
	}
};

void test()
{
	Son s;
}

int main()
{
	test();

	return EXIT_SUCCESS;
}
  • 继承和组合的混搭

先调用父类的构造,然后调用成员对象的构造,最后调用本身的构造,析构函数反之

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class A
{
public:
	A()
	{
		cout << "A的构造函数" << endl;
	}

	~A()
	{
		cout << "A的析构函数" << endl;
	}
};

class B
{
public:
	B()
	{
		cout << "B的构造函数" << endl;
	}

	~B()
	{
		cout << "B的析构函数" << endl;
	}
};

class C
{
public:
	C()
	{
		cout << "C的构造函数" << endl;
	}

	~C()
	{
		cout << "C的析构函数" << endl;
	}
};


class D:public A
{
public:
	D()
	{
		cout << "D的构造函数" << endl;
	}

	~D()
	{
		cout << "D的析构函数" << endl;
	}

public:
	B b;
	C c;
};

void test()
{
	D d;
}

int main()
{
	test();

	return EXIT_SUCCESS;
}

先调用A的构造函数,在调用B C 的构造函数 最后调用D的构造函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		cout << "Father的构造函数" << endl;
	}

	~Father()
	{
		cout << "Father的析构函数" << endl;
	}
};

class Son:public Father
{
public:
	Son()
	{
		cout << "Son的构造函数" << endl;
	}

	~Son()
	{
		cout << "Son的析构函数" << endl;
	}
};

class A
{
public:
	A()
	{
		cout << "A的构造函数" << endl;
	}
	~A()
	{
		cout << "A的析构函数" << endl;
	}
public:
	Son s;
};

class B
{
public:
	B()
	{
		cout << "B的构造函数" << endl;
	}

	~B()
	{
		cout << "B的析构函数" << endl;
	}
};

class C
{
public:
	C()
	{
		cout << "C的构造函数" << endl;
	}

	~C()
	{
		cout << "C的析构函数" << endl;
	}
};


class D:public A
{
public:
	D()
	{
		cout << "D的构造函数" << endl;
	}

	~D()
	{
		cout << "D的析构函数" << endl;
	}

public:
	B b;
	C c;
};

void test()
{
	D d;
}

int main()
{
	test();

	return EXIT_SUCCESS;
}

先调用父类A的成员对象的父类的构造函数

三、继承中同名成员的处理方法

  • 当子类和父类有相同的同名成员的时候,子类会隐藏父类的同名成员
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		a = 10;
	}
public:
	int a;
};

class Son:public Father
{
public:
	Son()
	{
		a = 20;
	}
public:
	int a;
};

void test()
{
	Son s;
	cout << s.a << endl;// 访问的是自己的成员变量
}

int main()
{
	test();
	return EXIT_SUCCESS;
}

可以通过作用域访问父类的同名成员变量

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		a = 10;
	}
public:
	int a;
};

class Son:public Father
{
public:
	Son()
	{
		a = 20;
	}
public:
	int a;
};

void test()
{
	Son s;
	cout << s.a << endl;// 访问的是自己的成员变量

	// 可以通过作用域来访问父类的成员变量
	cout << s.Father::a << endl;
}

int main()
{
	test();
	return EXIT_SUCCESS;
}
  • 当子类和父类有同名函数的时候,父类的所有函数重载都会被隐藏完毕
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		a = 10;
	}

	void func()
	{
		cout << "Father func" << endl;
	}

	void func(int a)
	{
		cout << "Father func1" << endl;
	}

	void func(int a,int b)
	{
		cout << "Father func a b" << endl;
	}

public:
	int a;
};

class Son:public Father
{
public:
	Son()
	{
		a = 20;
	}

	void func()
	{
		cout << "Son func" << endl;
	}

public:
	int a;
};

void test()
{
	
	Son s;
	s.func();// 调用的是子类的 同名成员函数
	s.func(1);// 不行  子类没有和父类的同名成员函数
}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

可以通过作用域来访问同名函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	Father()
	{
		a = 10;
	}

	void func()
	{
		cout << "Father func" << endl;
	}

	void func(int a)
	{
		cout << "Father func1" << endl;
	}

	void func(int a,int b)
	{
		cout << "Father func a b" << endl;
	}

public:
	int a;
};

class Son:public Father
{
public:
	Son()
	{
		a = 20;
	}

	void func()
	{
		cout << "Son func" << endl;
	}

public:
	int a;
};

void test()
{
	
	Son s;
	s.func();// 调用的是子类的 同名成员函数
	s.Father::func(1);// 通过作用域进行访问
}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

四、继承中的静态成员特性

静态成员可以被继承

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	static int mA;
};

// 静态成员类内部声明  类外进行访问
int Father::mA = 10;

class Son :public Father
{
public:

};

void test()
{
	Son s;
	cout << s.mA << endl;// 静态成员可以被继承

}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

子类同名的静态成员会覆盖掉父类的同名静态成员

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	static int mA;
};

// 静态成员类内部声明  类外进行访问
int Father::mA = 10;

class Son :public Father
{
public:
	static int mA;
};


// 子类同名的静态成员会覆盖父类的同名静态成员
int Son::mA = 100;

void test()
{
	Son s;
	cout << s.mA << endl;// 静态成员可以被继承 

}

int main()
{
	test();
	return EXIT_SUCCESS;
}

继承中的静态成员函数中,当子类和父类同名函数时候,父类的所有重载静态函数都会被隐藏

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	// 静态成员函数
	static void func()
	{
		cout << "Father func()" << endl;
	}

	// 静态成员函数重载
	static void func(int a)
	{
		cout << "Father func(int a)" << endl;
	}

	static void func(int a,int b)
	{
		cout << "Father func(int a,int b)" << endl;
	}

public:
	static int mA;
};

// 静态成员类内部声明  类外进行访问
int Father::mA = 10;

class Son :public Father
{
public:
	static void func()
	{
		cout << "Son func()" << endl;
	}

public:
	static int mA;
};


// 子类同名的静态成员会覆盖父类的同名静态成员
int Son::mA = 100;

void test()
{
	Son s;
	s.func();
	s.func(1);// 保存  父类的同名静态函数会被隐藏

}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

  • 从父类继承过来的静态成员变量是父类的静态成员变量 不是拷贝过来的
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father
{
public:
	// 静态成员函数
	static void func()
	{
		cout << "Father func()" << endl;
	}

	// 静态成员函数重载
	static void func(int a)
	{
		cout << "Father func(int a)" << endl;
	}

	static void func(int a,int b)
	{
		cout << "Father func(int a,int b)" << endl;
	}

public:
	static int mA;
};

// 静态成员类内部声明  类外进行访问
int Father::mA = 10;

class Son :public Father
{
public:
	static void func()
	{
		cout << "Son func()" << endl;
	}

public:
	static int mA;
};


// 子类同名的静态成员会覆盖父类的同名静态成员
int Son::mA = 100;

void test()
{
	Son s;
	cout << s.mA << endl;

	// 通过子类更改父类的静态成员变量
	s.Father::mA = 200;
	cout << Father::mA << endl;

	// 通过打印地址 查看是否更改同一个变量地址
	cout << &(s.Father::mA) << endl;
	cout << &(Father::mA) << endl;

}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

五、多继承

  • 多继承是一个类有两个以上的父类
  • 多继承的问题是,当父类中有同名的成员时,子类会产生二义性问题
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

class Father1
{
public:
	int bmw;
};

class Father2
{
public:
	int bmw;
};

class Son :public Father1, public Father2
{

};

void test()
{
	Son s;// 产生二义性问题
}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

六、菱形继承

两个派生类同时继承同一个基类,而又有某个类同时继承两个派生类,这种继承被称为菱形继承,或者钻石型继承

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qkgXnDXK-1667477462245)(…/images/3889f11618c5e7ad2f0bc10cfb5f6952accdf71072fbcf9ef796f569ae8903f5.png)]

虚基类的定义:被虚继承的基类称之为虚基类

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 称之为虚基类
class Animal
{
public:
	Animal()
	{
		mA = 100;
	}
public:
	int mA;
};

// 虚继承
class Sheep :virtual public Animal
{

};

// 虚继承
class Camel :virtual public Animal
{

};

class SheepCamel :public Sheep, public Camel
{
	// 多继承
	// 使用虚继承的方法解决菱形继承中的二义性问题
	

};

void test()
{
	SheepCamel s;

	// 直接使用组类的成员变量
	cout << s.mA << endl;// 打印100
	
}
 
int main()
{
	test();
	return EXIT_SUCCESS;
}

两个父类中有组类中的数据,然后子类会继承两个父类的数据,会产生二义性问题

解决二义性问题的关键是使用父类虚继承组类,使用virtual关键字

虚继承的原理:

  • 编译给类添加了一个指针,指针指向类似于表的组织,该表记录了该指针距离变量的偏移量
  • 当子类多继承两个父类,那么只有一份成员变量,然后又有两个指针,只有一份成员变量,所以不会产生二义性问题

七、通过指针访问成员变量

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;

// 称之为虚基类
class Animal
{
public:
	Animal()
	{
		mA = 100;
	}
public:
	int mA;
};

// 虚继承
class Sheep :virtual public Animal
{

};

// 虚继承
class Camel :virtual public Animal
{

};

class SheepCamel :public Sheep, public Camel
{
	// 多继承
	// 使用虚继承的方法解决菱形继承中的二义性问题

};

void test()
{
	SheepCamel s;
	cout << s.mA << endl;// 打印100
	
}

void test1()
{
	Sheep s;
	cout << *((int*)*(int*)&s + 1) << endl;

	// 将类型转换为Animal指针类型
	cout << ((Animal*)((char*)&s + *((int*)*(int*)&s + 1)))->mA << endl;
}
 
int main()
{
	test1();
	return EXIT_SUCCESS;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少写代码少看论文多多睡觉

求打赏,求关注,求点赞

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值