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);
};
相关推荐
伍六星7 分钟前
更新Java的环境变量后VScode/cursor里面还是之前的环境变量
java·开发语言·vscode
Dola_Pan10 分钟前
Android四大组件通讯指南:Kotlin版组件茶话会
android·开发语言·kotlin
半桔20 分钟前
【算法深练】分组循环:“分”出条理,化繁为简
数据结构·c++·算法·leetcode·面试·职场和发展
万能程序员-传康Kk22 分钟前
智能教育个性化学习平台-java
java·开发语言·学习
道剑剑非道26 分钟前
QT开发技术【ffmpeg + QAudioOutput】音乐播放器
开发语言·qt·ffmpeg
@残梦32 分钟前
129、QT搭建FFmpeg环境
开发语言·qt·ffmpeg
序属秋秋秋1 小时前
《C++初阶之类和对象》【命名空间 + 输入&输出 + 缺省参数 + 函数重载】
开发语言·c++·笔记
C_Liu_1 小时前
C语言:数据在内存中的存储
c语言·开发语言
武子康1 小时前
Java-39 深入浅出 Spring - AOP切面增强 核心概念 通知类型 XML+注解方式 附代码
xml·java·大数据·开发语言·后端·spring
Kethy__1 小时前
算法分析与设计-动态规划、贪心算法
c++·学习·算法·贪心算法·动态规划