c++中模版进阶和继承

类型参数+非类型模版参数

cpp 复制代码
//类型参数+非类型模版参数
template<class T,int N>
class Array
{
public:
	Array() {}
private:
	T _a[N];
};
int main()
{
	Array<int, 100> a1;

	return 0;
}

注意:

  1. 浮点数、类对象以及字符串是不允许作为非类型模板参数的。

  2. 非类型的模板参数必须在编译期就能确认结果。

模版的特化

通常情况下,使用模板可以实现一些与类型无关的代码,但对于一些特殊类型的可能会得到一些错误的结 果

cpp 复制代码
template<class T>
bool IsEqual(T& left, T& right)
{
	return left == right;
}
//特化
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
	return strcmp(left, right) == 0;
}
int main()
{
	//Array<int, 100> a1;
	int a = 0, b = 1;
	cout << IsEqual(a, b) << endl;
	const char* p1 = "hello";
	const char* p2 = "world";
	cout << IsEqual(p1, p2) << endl;
	return 0;
}

全特化

全部参数都特化

cpp 复制代码
template<>
bool IsEqual<char*>(char*& left, char*& right)
{
	return strcmp(left, right) == 0;
}

偏特化

可以是特化部分参数/或者对参数进行进一步的限制

cpp 复制代码
template<class T2>
class Date<int T2>
{};
cpp 复制代码
template<class T1,class T2>
class Data<T1*,T2*>
{};

模板分离编译

什么是分离编译

一个程序(项目)由若干个源文件共同实现,而每个源文件单独编译生成目标文件,最后将所有目标文件链 接起来形成单一的可执行文件的过程称为分离编译模式。

【Linux】编译器-gcc/g++的使用(预处理、编译、汇编、连接)

【Linux】编译器-gcc/g++的使用(预处理、编译、汇编、连接)_g++ 预编译-CSDN博客https://blog.csdn.net/dhgiuyawhiudwqha/article/details/136849183

同样是分离编译,普通函数/类可以,函数模版/类模版不行。

模版定义时不会实例化,使用时才会

Func.o中有定义但是却不知道要实例化为什么类型

test.o中有声明但是没有定义 故链接时会发生报错

Func.o中有符号表,表中有函数地址。

链接会将目标文件结合到一起,有声明没有定义即可编译通过,链接时在Func.o中找函数地址,函数地址存在才能编译通过。

显示实例化

cpp 复制代码
#include"Func.h"


void F1()
{
	cout << "F1()" << endl;
}
template<class T>
void F2(const T& x)
{
	cout << "void F2(const T&x)" << endl;
}
//显示实例化
template
void F2<int>(const int& x);

解决此问题的另一种方法比较粗暴就是直接将其全放入.h文件中。

继承

继承的概念

继承(inheritance)机制是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性的基础上进行扩展,增加功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了由简单到复杂的认知过程。以前我们接触的复用都是函数复用,继承是类设计层次的复用。

cpp 复制代码
class Person
{
public:
 void Print()
 {
 cout << "name:" << _name << endl;
 cout << "age:" << _age << endl;
 }
protected:
 string _name = "peter"; // 姓名
 int _age = 18; // 年龄
};
 
// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了Student和
Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可以看到变量的复用。
调用Print可以看到成员函数的复用。
class Student : public Person
{
protected:
int _stuid; // 学号
};
 
class Teacher : public Person
{
protected:
 int _jobid; // 工号
};
 
int main()
{
 Student s;
 Teacher t;
 s.Print();
 t.Print();
 
 return 0;
}

继承定义

类中的私有和保护在当前类没差别。

在继承后的子类中有差别,private的成员在子类中不可见。

总结:

  1. 基类private成员在派生类中无论以什么方式继承都是不可见的。这里的不可见是指基类的私有成员还是 被继承到了派生类对象中,但是语法上限制派生类对象不管在类里面还是类外面都不能去访问它。

  2. 基类private成员在派生类中是不能被访问,如果基类成员不想在类外直接被访问,但需要在派生类中能 访问,就定义为protected。可以看出保护成员限定符是因继承才出现的。

  3. 实际上面的表格我们进行一下总结会发现,基类的私有成员在子类都是不可见。基类的其他成员在子类 的访问方式 == Min(成员在基类的访问限定符,继承方式),public > protected > private。 4. 使用关键字class时默认的继承方式是private,使用struct时默认的继承方式是public,不过最好显示的 写出继承方式。

  4. 在实际运用中一般使用都是public继承,几乎很少使用protetced/private继承,也不提倡使用 protetced/private继承,因为protetced/private继承下来的成员都只能在派生类的类里面使用,实际中 扩展维护性不强。

子类和父类之间的赋值兼容规则

1.子类对象可以赋值给父类对象/指针/引用(切片)

当父类和子类同时有同名成员时,子类的成员隐藏 了父类的成员。(重定义

cpp 复制代码
// B中的fun和A中的fun不是构成重载,因为不是在同一作用域
// B中的fun和A中的fun构成隐藏,成员函数满足函数名相同就构成隐藏。
class A
{
public:
 void fun()
 {
 cout << "func()" << endl;
 }
};
class B : public A
{
public:
 void fun(int i)
{
 A::fun();
 cout << "func(int i)->" <<i<<endl;
 }
};
 
void Test()
{
 B b;
 b.fun(10);
};
相关推荐
阿珊和她的猫4 小时前
v-scale-scree: 根据屏幕尺寸缩放内容
开发语言·前端·javascript
fouryears_234176 小时前
Flutter InheritedWidget 详解:从生命周期到数据流动的完整解析
开发语言·flutter·客户端·dart
我好喜欢你~7 小时前
C#---StopWatch类
开发语言·c#
lifallen8 小时前
Java Stream sort算子实现:SortedOps
java·开发语言
IT毕设实战小研8 小时前
基于Spring Boot 4s店车辆管理系统 租车管理系统 停车位管理系统 智慧车辆管理系统
java·开发语言·spring boot·后端·spring·毕业设计·课程设计
快乐的划水a8 小时前
组合模式及优化
c++·设计模式·组合模式
cui__OaO10 小时前
Linux软件编程--线程
linux·开发语言·线程·互斥锁·死锁·信号量·嵌入式学习
星星火柴93610 小时前
关于“双指针法“的总结
数据结构·c++·笔记·学习·算法
鱼鱼说测试10 小时前
Jenkins+Python自动化持续集成详细教程
开发语言·servlet·php
艾莉丝努力练剑10 小时前
【洛谷刷题】用C语言和C++做一些入门题,练习洛谷IDE模式:分支机构(一)
c语言·开发语言·数据结构·c++·学习·算法