C++ 特性 --内部类 模板类中取出来类类型问题
一 . 内部类的基本特性
一段小demo如下
// 内部类
using namespace std;class Outer {
private:int m_privateVar = 10; // 私有非静态成员static int m_staticVar; // 私有静态成员public:// 公有内部类class PublicInner {public:void accessOuter(Outer& outer) {// 访问外部类的私有静态成员cout << "Static Var: " << m_staticVar << endl;// 访问外部类的私有非静态成员(需对象)cout << "Private Var: " << outer.m_privateVar << endl;}};// 私有内部类(仅在Outer内部可用)class PrivateInner {public:void secret() { cout << "This is a private inner class." << endl; }};void usePrivateInner() {PrivateInner p;p.secret(); // 只能在Outer内部调用}
};// 初始化静态成员
int Outer::m_staticVar = 20;int main() {// 实例化公有内部类Outer::PublicInner inner;Outer outer;inner.accessOuter(outer); // 输出:Static Var: 20,Private Var: 10// 尝试访问私有内部类(会报错)// Outer::PrivateInner p; // 错误:PrivateInner是私有的// 调用外部类的公有方法间接使用私有内部类outer.usePrivateInner(); // 输出:This is a private inner class.return 0;
}
小结:
1. 内部类是外部类的天生友元,对于外部类的非静态成员变量直接访问无需类名。
2. 私有的内部类,只能被外部类看见,public修饰的内部类只能在外部类内部可见
3. 我们可以通过sizeof() 发现内部类是独立于外部类的
二. 关于从一个模板类中取出一个类来使用出错的情况
using namespace std;// 非模板类:外部类含公有内部类
class Outer {
public:class Inner { // 公有内部类public:void print() { cout << "Outer::Inner\n"; }static int count;};
};
// 对于静态成员变量的初始化我们只能在类外做避免每次创建对象都 重复定义 静态成员与对象无关
int Outer::Inner::count = 0; // // 模板类:内部类依赖模板参数
template <typename T>
class TemplateOuter {public:class Nested { // 模板类的内部类public:using Type = T; // 嵌套类型别名static T value; // 静态成员变量void print() {cout << "这里是模板类的内部类" << endl;}};
};
// 初始化模板静态成员
template <typename T>
T TemplateOuter<T>::Nested::value = T();// 1. 非模板场景:直接访问内部类(无需typename)
void nonTemplateCase() {Outer::Inner obj; // 正确:Outer是具体类型,编译器明确Inner是类obj.print();
}template <typename T>
void templateCase() {Outer::Inner in;TemplateOuter<T>::Nested n;// 正确写法:用typename声明这是类型typename TemplateOuter<T>:: Nested obj1;obj1.print(); // 调用内部类方法// 访问内部类的类型别名(也需typename)}int main() {nonTemplateCase();templateCase<TemplateOuter<int>>();return 0;
}
理解一个简单的事情 对于静态成员变量的定义都会在类外,具体可以参考如上注释,其次就是这里要谈为什么对于一个模板类中期待取出一个其他的类(这里的demo是一个内部类)会出现提示你加上typename,但是对于对于非模板类(template<class T>类似这样的)却不没有这样的提示要求你加上typename关键字呢。
这个就需要你深刻理解对于C++关于模板实例化的编译器做了什么了?
泛型编程(利用模板)中我们的模板实例化是在编译器,在编译阶段1. 先检查一下语法,像代码有没有少; 以及相关类型赋值 声明定义等有没有问题(这是模板还没有实例化),所以这时候你用一个如A<T>:: B b; 你用一个A<T> 类本义想取出来B类但是编译器说: 我还没实例化呢你就直接给我弄了一个变量了,那我不管在我眼里我又不知道现在这个A类具体是什么样的(因为还没实例化编译器不知道A类内部细节)所以它就为觉得: 你B要么是一个静态变量要么是一个类 这样的二义性。
所以强烈要求你加上 typename 主动告诉编译器: 我就是一个类 放心大胆的用吧!