类模板与普通类:
- 一些需要强调一下的知识:
在一个类中使用另一个类的公有成员
能够将另一个类作为返回值类型
同样,普通的类可以做的事模板类也可以做。
#include<iostream>
using namespace std;
struct A {
int num;
};
class B {
//这里给类A声明了一个别名。
//只要位于同样一个作用域中类之间的public数据成员就可以互相访问
//也可以在这一个类中使用到别的类,不需要额外的声明什么东西。
typedef A Anything;
private:
int num;
public:
B(int x) {
num = x;
}
Anything& Reverse() {
Anything a_temp;
a_temp.num = 4*num;
return a_temp;
}
};
int main() {
B b(3);
A a = b.Reverse();
cout << a.num << endl;
}
上面代码即显示了使用在类B中使用结构体A的内容。如果为class A
那么需要将里面的内容声明为public
。
typedef的使用:
在模板的最上边使用public声明了一个数据类型表。typedef
**仅仅声明了这个模板类的别名,没有把另外一个类当作此类的数据成员。**即不能说类的数据成员是一个类!
即便类不是数据成员,我们依然可以在类模板中使用其他的类。如果在同一个源文件中就可以直接使用,如果是在不同的文件中只需要使用
#include
指令就可以了。
这里贴出来MyList
的数据类型表。
template<typename T>
struct MyList_Node {
//没有<T>
MyList_Node<T>* prev;
MyList_Node<T>* next;
T value;
};
template<typename T>
struct MyList_iterator {
typedef MyList_iterator<T> iterator;
typedef MyList_Node<T>* link_type;
link_type node;
//other codes
};
template<typename T>
class MyList {
public:
typedef MyList_iterator<T> iterator;
protected:
MyList_Node<T>* TailNode;//链表尾指针
size_t len;
};
可以看出在10,11,18行都使用了typedef
命名了一个别名,并且接收的参数都是模板类类型,原因是这些类型的长度过于长不方便接下来使用,所以说就娶了一个直观易懂的别名。
MyList<iterator<int>>与MyList<int>::iterator
这个东西在我刚接触C++模板的时候是很迷惑的,我迷惑在哪里了呢?我把第二种形式当成了与第一种情况相同。即类模板
Mylist<T>
的模板参数T接受了一个类类型的泛型。
既然MyList<T>
的T接受一个iterator<T>
,那么就等价于MyList<T>::iterator
上面的逻辑简直是个神逻辑,自己脑补了下C++有这种神奇的功能。
以上就是这几天迷惑的根源,明白之后才知道自己有多蠢…
①MyList<iterator<int>>
②MyList<int>::iterator
- 第一种情况:
①说的是泛型MyList<T>
的泛型参数T接受了iterator<int\>
参数,即iterator作为一个类类型来实例化MyList类中的成员。 - 第二种情况:
②说的是泛型接受一个int
类型,然后::
运算符说明MyList<int>
类型里面有一个数据类型是iterator
(typedef
命名的别名,原名是iterator<T>
,因为这里MyList
的泛型参数为int
,所以iterator
中的泛型参数也为int。
无意中发现很有意义的问题:
- [Question]
为什么对MyList<T>使用::
运算符之后可以接着iterator
?
可以看出除了typedef外就与iterator没啥关系了,那么我猜测一下可能与::
运算符有关!
那么写几行代码来试验一下。
#include<iostream>
class B {
public:
int num;
B() { num = 0; }
};
class Try {
public:
//typedef B Bre;
int int_type;
double double_type;
private:
int pint;
double pdouble;
};
int main() {
Try::Bre a;
std::cout << a.num;
}
- 没有第九行的时候,在
Try
后键入::
运算符代码提示如下,说明此时我们可以使用的是Try
类中的两个public类型数据成员。
- 而有第九行的时候,在
Try
后键入::
运算符代码提示如下,说明此时我们不仅可以使用的是Try
类中的两个public类型数据成员,**更可以使用使用typedef
引入的·class B
de的别名Bre,可见typedef还有一个功能就是把一个类型声明为类的类型成员,这时候就可以使用通过双冒号时使用这些类型成员了。
那么在这种情况下,在MyList
中使用
typedef MyList_iterator<T> iterator;
语句即可完成将iterator类型声明为MyList
中的类型成员,也即可以通过
MY=yList<T\>::iterator iter
来定义一个MyList_iterator<T>
的变量。