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);
};
相关推荐
阿史大杯茶几秒前
AtCoder Beginner Contest 381(ABCDEF 题)视频讲解
数据结构·c++·算法
陌小呆^O^9 分钟前
Cmakelist.txt之win-c-udp-server
c语言·开发语言·udp
C++忠实粉丝9 分钟前
计算机网络socket编程(3)_UDP网络编程实现简单聊天室
linux·网络·c++·网络协议·计算机网络·udp
Gu Gu Study16 分钟前
枚举与lambda表达式,枚举实现单例模式为什么是安全的,lambda表达式与函数式接口的小九九~
java·开发语言
时光の尘30 分钟前
C语言菜鸟入门·关键字·float以及double的用法
运维·服务器·c语言·开发语言·stm32·单片机·c
我们的五年35 分钟前
【Linux课程学习】:进程描述---PCB(Process Control Block)
linux·运维·c++
以后不吃煲仔饭44 分钟前
Java基础夯实——2.7 线程上下文切换
java·开发语言
进阶的架构师1 小时前
2024年Java面试题及答案整理(1000+面试题附答案解析)
java·开发语言
前端拾光者1 小时前
利用D3.js实现数据可视化的简单示例
开发语言·javascript·信息可视化
程序猿阿伟1 小时前
《C++ 实现区块链:区块时间戳的存储与验证机制解析》
开发语言·c++·区块链