星锐网站建设,深圳外贸人才网,网站建设一般多少个板块,jsp环保主题网站代做继承 2.1结构体成员权限2.1.1访问权限2.1.2类与结构体 2.2类的成员函数2.2.1类内规则2.2.2类成员内联函数inline 2.3类的继承2.3.1类的继承与成员函数2.3.2类的多继承2.3.2.1类的多继承#xff1a;菱形问题提出 2.3.3类的虚继承#xff08;关键字virtual#xff09; 2.4友元… 继承 2.1结构体成员权限2.1.1访问权限2.1.2类与结构体 2.2类的成员函数2.2.1类内规则2.2.2类成员内联函数inline 2.3类的继承2.3.1类的继承与成员函数2.3.2类的多继承2.3.2.1类的多继承菱形问题提出 2.3.3类的虚继承关键字virtual 2.4友元2.4.1友元类2.4.2友元函数 2.5构造函数和析构函数2.6初始化列表 2.1结构体成员权限
2.1.1访问权限
访问权限有三种 public 公共权限类内可以访问类外可以访问
protected 保护权限类内可以访问类外不可以访问子类可以访问父类中的保护内容
private 私有权限类内可以访问类外不可以访问子类不可以访问父类中的私有内容
注意protected 和 private 的设计是为了继承
2.1.2类与结构体
类 类在游戏开发中用的最多 如果没有在类中显式定义构造函数和析构函数并指定访问权限则默认情况下它们的权限都是公有的public 结构体 结构体一般用于储存变量或数据 结构体也有构造初始化和析构释放内存等不写编译器就会默认生成在游戏中对对象的生命周期的操作
#includeiostream
using namespace std;
struct Test01
{
public:int a;void test01() {}
protected:int b;void test02() {}
private:float c;void test03() {}
};
class Test02
{
public:int d;void test04() {}
protected:int e;void test05() {}
private:float f;void test06() {}
};
int main()
{Test01 A;A.a 10;int num1 A.a;A.test01();//A.c;//因为设置了保护权限所以不可以访问//A.test03();//因为设置了私有权限所以不可以访问Test02 B;B.d 20;int num2 B.d;B.test04();//B.e;//因为设置了保护权限所以不可以访问//B.test06();//因为设置了私有权限所以不可以访问system(pause);return 0;
}2.2类的成员函数
2.2.1类内规则
类内可以写静态函数、成员函数 静态函数不可以调用成员函数成员函数可以调用静态函数 静态函数内不可以包含类内的成员信息如果想调用需要使成员信息也变为静态 全局的调用方式::
#includeiostream
using namespace std;
int Fun1()
{return 1;
}class Test01
{
public:Test01();~Test01();static int a;static int b;static int Fun1()//类内可以添加静态函数{return ab; //无法直接调用int a;和int b;需要转换为static形式}int Fun2()//类内可以添加成员函数{Test01::Fun1();//成员函数可以调用静态函数return 3;}
};
int Test01::a 0;
int Test01::b 0;
Test01::Test01()
{int num1 ::Fun1();//::调用全局范围中的cout num1 endl;
}
Test01::~Test01()
{}struct Test02
{
public:static void Fun1();
};void Test02::Fun1() {}
int main()
{Test01 A;//实例化Test01::Fun1();A.Fun1();A.Fun2();Test02::Fun1();system(pause);return 0;
}2.2.2类成员内联函数inline 为什么inline的效率会高效因为编译时编译器会把代码副本放在每个调用函数的地方 可以使用在类成员内也可以使用在全局中也可以使用在结构体内
将简短的、频繁调用的函数声明为内联函数可以获得较好的效果。但是对于复杂的函数或者在循环中调用的函数使用内联可能导致代码膨胀反而会影响性能如for、switch、递归等。
ue4中的FORCEINLINE也代表着内敛的效果使用FORCEINLINE使需要包含头文件“CoreMinimal.h”
#includeiostream
using namespace std;
class Test01
{
public://想要获取私有成员不想私有成员被赋值可以用inline//比下面注释中的代码高效很多inline int Geta()const{return a;}/*int Geta()const{return a;}*/
private:int a;
};inline int Getb()
{return 0;
}struct Test02
{
public:inline int Getc()const{return c;}
private:int c;
};int main()
{Test01 A;A.Geta();Getb();Test02 C;C.Getc();system(pause);return 0;
}2.3类的继承
2.3.1类的继承与成员函数
父类也成为基类子类也称为派生类 封装SDK插件时只需要封装基类其他人使用时只需要继承即可使用其中的方法或者去扩展 游戏开发时大部分用的都是公共继承
//public
// public public
// protected protected
// private private
//provected
// public protected
// protected protected
// private private
//private
// public private
// protected private
// private private2.3.2类的多继承
使用场景如下列代码将每一个系统部分封装到各个模块中需要使用时直接调用即可非常方便 可以将对象转换成某个模块 不需要直接转换成类可以直接调接口三个指针指向不同的继承接口所以可以直接通过指针
#includeiostream
using namespace std;
class UObject
{};class AActor :public UObject//只管和对象有关的
{
public:void Start() {}void End() {}void Net() {}
};class IPhysics//只管物理
{
public:void Simulate() {}
};class IAttack//攻击接口
{
public:void AttackTarget(ACharacter* InTarget) {}
};class ACharacter :public AActor,public IPhysics,public IAttack
{};bool IsSimulate(IPhysics* p)//好处是不需要直接转换成类可以直接调接口
{if (p){p-Simulate();}return true;
}
int main()
{ACharacter A;//多继承ACharacter B;A.Start();A.End();A.Simulate();A.AttackTarget(B);//A为多继承的继承了IPhysics、IAttack、AActorIPhysics* p A;
//因为A继承了IPhysics接口通过ACharacter类的多继承
//A对象可以被视为一个IPhysics对象
//将A对象的地址赋值给指针p就可以通过指针p来访问A对象的IPhysics接口IAttack* p1 A;AActor* p2 A;IsSimulate(A);system(pause);return 0;
}2.3.2.1类的多继承菱形问题提出 A的类型为ACharacter同时继承了AActor和UHello而AActor和UHello同时继承了UObject用A调用UObject时会出现二义性不知道调用的是AActor的UObject还是UHello的UObject A.Destroy();调用的是UHello的还是AActor的 这既是菱形问题要避免 解决菱形问题需要用到虚函数在下文会解决 #includeiostream
using namespace std;
class UObject
{
public:void Destroy() {}
};class AActor :public UObject//只管和对象有关的
{
public:void Start() {}void End() {}void Net() {}
};class UHello :public UObject
{};class IPhysics//只管物理
{
public:void Simulate() {}
};class ACharacter;//因为class ACharacter在后面所以先声明也可以在IAttak内部使用前加class
class IAttack//攻击接口
{
public:void AttackTarget(class ACharacter* InTarget) {}
};class ACharacter :public AActor,public IPhysics,public IAttack,public UHello
{};bool IsSimulate(IPhysics* p)//好处是不需要直接转换成类可以直接调接口
{if (p){p-Simulate();}return true;
}
int main()
{ACharacter A;IPhysics* p A;IAttack* p1 A;AActor* p2 A;IsSimulate(A);//A.Destroy();//会报错类型不明确//调用的是UHello的还是AActor的system(pause);return 0;
}2.3.3类的虚继承关键字virtual
虚继承使class B和class C继承的public A变成一个共享的类因此class D只用调用一次A 尽量避免虚继承问题
#includeiostream
using namespace std;
class A
{
public:A(){printf(A\n);}void Hello(){printf(Hello\n);}
};
class B :virtual public A
{
public:B() :A() {}
};
class C :virtual public A
{
public:C() :A() {}
};
class D :public B, public C
{
public:D()//c保错编译器不知道构造B还是C{}~D() {}
};
int main()
{D d;d;//没虚继承前输出结果为A输出了两次//A//Ad.Hello();//正常情况下会报错在class B和C的继承public A前加上virtual变为虚继承//输出结果为//A//Hellosystem(pause);return 0;
}2.4友元
2.4.1友元类
使用友元可以访问另一个类内的所有内容
#includeiostream
using namespace std;
class FTestClass
{friend class FTest2;//友元
public:void Hello() {}
private:void Hello1() {}void Hello2() {}void Hello3() {}
protected:void Hello4() {}
};class FTest2
{
public:void Init(){Class.Hello();Class.Hello1();//因为是private权限正常会报错使用友元不会报错Class.Hello4();//因为是protected权限正常会报错使用友元不会报错}
private:FTestClass Class;
};int main()
{FTest2 Test2;Test2.Init();system(pause);return 0;
}2.4.2友元函数
友元不能被继承 优点提高了程序的运行效率 缺点破坏了类的封装以及稳点性 友元关系本身不具备继承性
#includeiostream
using namespace std;
class FTest1
{
public:friend void Printf_f(FTest1 T){T.Hello();printf(%d\n, T.a);printf(%d\n, T.b);}void Printf_a(){printf(%d\n, a);printf(%d\n, b);printf(%d\n, c);}int c 100;static void Printf_b(FTest1 T){T.Hello();printf(%d\n, T.a);printf(%d\n, T.b);}
private:void Hello(){a 0;//其实是this-a0;编译器省略了b 10;}
private:int a;int b;
};int main()
{FTest1 A;Printf_f(A);A.Printf_a();FTest1::Printf_b(A);//静态函数system(pause);return 0;
}2.5构造函数和析构函数
#includeiostream
using namespace std;
class FTest1
{
public:};class FTestA
{
public:FTestA();FTestA(int ina, int inb, int inc);~FTestA();
public:int a;int b;int c;FTest1* T;
};FTestA::FTestA()
{a 1;b 2;c 3;
}FTestA::FTestA(int ina, int inb, int inc)
{a ina;b inb;c inc;T new FTest1();//分配内存
}FTestA::~FTestA()
{if (T){delete T;T nullptr;//将指针类型的变量 T 初始化为空指针}
}int main()
{FTestA A;//会走FTestA::FTestA()cout A.a A.b A.c endl;FTestA B(10,20,30);//会走FTestA(int ina, int inb, int inc);cout B.a B.b B.c endl;system(pause);return 0;
}2.6初始化列表
初始化列表的语法是在构造函数的参数列表后使用冒号 “:”接着是多个初始化器每个初始化器由成员变量名和对应的初始值用逗号分隔。 有父类时父类排在最前面 一定要按照变量声明的顺序排列
初始化列表的优点 初始化非静态常量成员变量对于非静态常量成员变量它们只能在初始化列表中进行赋值不能在构造函数中赋值。 初始化引用成员变量引用成员变量必须在构造函数中进行初始化并且只能使用初始化列表进行初始化。 初始化基类成员变量如果派生类包含一个基类那么初始化列表可以用于调用基类的构造函数并初始化基类成员变量。 性能优化使用初始化列表可以避免先创建再赋值的过程提高效率。
注意 初始化列表只能在构造函数中使用 初始化顺序固定 初始化列表只能在编译时确定初始值无法在运行时根据条件或变量的值来决定初始值。 初始化列表中的初始化操作无法直接处理异常或错误。
#includeiostream
using namespace std;
class FTest1
{
public:};class FHello_F{};class FTestA:public FHello_F
{
public:FTestA();FTestA(int ina, int inb, int inc);~FTestA();
public:int a;int b;int c;FTest1* T;
};FTestA::FTestA()
{a 1;b 2;c 3;
}FTestA::FTestA(int ina, int inb, int inc)
//初始化列表:FHello_F()//有父类时放在最前面,a(ina)//一定要按照变量声明的顺序排列,b(inb),c(inc)
{T new FTest1();//分配内存
}FTestA::~FTestA()
{if (T){delete T;T nullptr;}
}int main()
{FTestA A;//会走FTestA::FTestA()cout A.a A.b A.c endl;FTestA B(10,20,30);//会走FTestA(int ina, int inb, int inc);cout B.a B.b B.c endl;system(pause);return 0;
}