嵌套类模块化问题
前言之前的模块化是编译成.lib。在单文件下还好,多文件下还是有点问题。
正文123456#pragma once#include"Weapon.h"class Hack{public: class Weapon;};
12345678#pragma once#include"Hack.h"class Hack::Weapon{public: int hp; int mp;};
12345678910#include<iostream>#include"Hack.h"#include"Weapon.h"int main(){ Hack::Weapon hw; return 0;}
发现编译器提示使用一个不完整的类。
但是当他们都写在.cpp源文件的时候反而不报错。
显然是头文件之间出现了问题。因为两个头文件相互引用,而预编译阶段就是展开头文件。所以当互相调用的时候,就不能确定先展开谁,因为无论先展开谁,都会有一个缺失了,导致类 ...
嵌套类
前言嵌套反正不是第一次用了,嵌套类还算陌生,毕竟友元不算。要说稍微接近一点的也是命名空间,但总归不是一个东西。
正文设计一个角色:
生命值
内力值
武器
强化等级
品阶
可能第一印象是用struct结构体,当然也没毛病,因为类用的少,得心应手还是结构体,不过反正要慢慢过渡。
定义嵌套类123456789101112131415#pragma onceclass Hack{public: int hp; int mp; class weapon{ short lv; enum weaponLv{ normal = 0, high, rare, myth }; };};
嵌套写法在结构层次上感知会更强,前提是里面的类不需要给别的类用,毕竟嵌套在里面作用域也就在里面了。
调用嵌套类就要用::表明作用域。比如这里的Hack::weapon lv;
注:嵌套类的作用域也受封装属性管辖,即private封装的结构体无法被外部调用。
既然已经学了文件分级写,那么.h就应该都是声明,定义都放在.c ...
友元
前言友元是一种定义在类外部的普通函数或类,但它需要在类体内进行说明,为了与该类的成员函数加以区别,在说明时前面加以关键字friend。友元不是成员函数,但是它可以访问类中的私有成员。
正文12345#pragma onceclass Box{ int hp; int mp;};
老样子写个类。
友元函数当类中成员没有声明是public的时候,即便你用类当参数模板,也是无法调用的。
123void test(Box &b){ b.hp = 100;}
结果就是无法访问。
而按照友元的逻辑,需要告诉这个类你有一个朋友,friend void test(Box &b);这样你的朋友才能了解你的相关事物。
然后就不会报错了。
说明友元访问私有变量是没啥问题,还能访问私有函数
1234//Box.hint getHp(){ return this->hp;}
12345//main.cppvoid test(Box &b){ b.hp = 100; std::cout < ...
静态成员变量和函数
前言成员变量就是class中定义的变量,不论是public下还是private下,都是这个类的成员变量那么静态成员变量,就是加上关键字static。
正文
静态成员变量静态变量的生命周期会随着程序结束才释放,而是脱离{}作用域。不过c++处理这种可能还是希望放在未命名的命名空间里。
因为static的生命周期要等到程序结束,所以说
所有类在实例化之后,共享类中的静态成员变量
而且类在没有实例化的情况下,静态变量已经有了空间,仍然可以访问到
那么可以说类的静态成员变量并不是完全属于类,就跟成员函数有点相似
12345#pragma onceclass Box{public: static int count;};
因为类的特殊性,所以静态成员变量也是无法直接初始化的。
你可以选择在外部初始化
1int Box::count = 100;
但是注意,这里是在Box类这个作用域下的count如果你是int count=100; 这是两个不相干的变量。
第一个特性其次是共享静态成员变量。也就是说当你某个实例化对象改变了count的值,其它 ...
hstring
前言有了基本的构造函数、拷贝函数、析构函数可以自己试着写个丐版的string。
正文
hstring str(“哈哈哈”); //构造函数
hstring strA(str); //拷贝函数
123456789101112131415#pragma onceclass hstring{public: hstring(){ } hstring(const hstring &hs){ } ~hstring(){ }};
大概框架就是这样,但是要注意,套string就没意思了。char或者char*的话要注意内存分配的事。
想了下大概是char*比较合适,毕竟初始化的时候鬼知道这个字符串多长。然后提到长度,还要写个成员变量,和成员函数去统计出这个长度。
构造12345678910111213141516171819202122232425262728293031323334#pragma onceclass hstring{pr ...
析构函数
前言构造函数是在类对象创建时就调用,一般的用途就是初始化对象。而析构函数相反,它是在类的对象结束生命周期才自动执行,一般就是清理之类的,最常见就是释放掉new的空间
格式也挺特殊,是在类名前加一个~全称:~类名(){}
正文析构函数名也应与类名相同,只是在函数名前面加一个位取反符,例如stud( ),以区别于构造函数。它不能带任何参数,也没有返回值(包括void类型)。只能有一个析构函数,不能重载。如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数(即使自定义了析构函数,编译器也总是会为我们合成一个析构函数,并且如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数再调用合成的析构函数),它也不进行任何操作。所以许多简单的类中没有用显式的析构函数。——百度
这个析构主要就是应对动态分配的内存,需要手动销毁,因为其它的成员变量该结束编译器会自动处理掉。
12345678910111213141516171819#include<iostream>class Box{public: Box(){ std::co ...
构造函数+1
前言继续了解构造函数
正文列表初始化构造函数最直接的就是初始化成员变量
1234567891011#pragma onceclass Hack{public: int hp; int mp; Hack(int hp,int mp){ this->hp = hp; this->mp = mp; }};
除了在函数里面初始化,还可以使用列表方式
12345678910#pragma onceclass Hack{public: int hp; int mp; Hack(int _hp, int _mp) :hp{ _hp },mp{_mp}{ }};
列表初始化的话就不能用this指针了,所以你要手动去区分开形参和成员变量,就是不要起一个名字
那么说这两种都是初始化的方法,谁更好答案是列表更好
效率高
在某些情况下只能用列表初始化
1234567891011121314#pragma onceclass Hack{public ...
构造函数
前言构造函数也是类的成员函数,但是比较特殊。类一共有两个特殊的函数,一个是构造函数,另一个是析构函数。
正文初始化123456#pragma onceclass Hack{public: int hp; int mp;};
123int main(){ Hack ha{100,200};}
在成员变量都为public属性时,可以通过这种方式顺序初始化。
打印一下看到值是正确被赋予了。
但是如果有个成员是私有的,那么这种顺序就被打乱了
1234567#pragma onceclass Hack{public: int hp;private: int mp;};
123int main(){ Hack ha{ 100,200 }; //error}
1是不匹配,2是设置的参数超了。
归根结底就是类型没有对上,那么新建个类,然后给指定的参数赋值,在拷贝给这个类。
12345int main(){ Hack ha; ha.hp = 100; Hack ...
const类
前言const肤浅的时候就是定义常量,跟#define类似。但是当实例化的类被限定为const类型的时候,又是一个搞怪点
正文123456789//Hack.h#pragma onceclass Hack{public: int hp; int mp; int lv;};
123456789#include<iostream>#include"Hack.h"int main(){ const Hack hc; hc.hp = 100; //error return 0;}
因为实例化的类被限定为了const,所以它也无法修改成员。
当然要修改一个const对象的时候,可以用指针+强转去逆它。
12const Hack *HCP = &hc;HCP->hp = 100;
这种方式仍然是不可取的,因为指针也被const修饰了,所以它也无法修改成员。还好前面指针还有印象,知道怎么玩
12Hack *HCP = (Hack*) &hc;HCP->hp = 100;
然后打印一下 ...
成员函数
前言1234567891011class ROLE{public: int hp; //成员变量 int mp; //成员变量 void Init(){ //成员函数 hpadd = 3; }private: int hpadd; //成员变量};
谁的成员,无非就是要知道作用域在哪里。
正文与常规函数不同
12345678910#include<iostream>int add(int a,int b){ return a + b;}int main(){ return 0;}
这个时候函数add是全局函数,搁哪调用都没问题。相反的,类中的成员函数,就只能被这个类调用。
12345678910class Box{public: void test(){ std::cout << "hello Box\n"; & ...