自定义数据类型
类
一种用户定义的引用[数据类型
类的基本概念
定义一个类:
class Player { public: //访问权限 int x, y; int speed; //变量 void Move(int ax, int ay) //方法 { x += ax * speed; y += ay * speed; } };
使用类实例化一个对象:
Player player0;
访问权限
一个类的所有成员默认情况下是私有成员
- private(私有成员)
只有类中的函数才能访问类中的变量。
- protected(保护成员)
- public(公有成员)
类之外的任何地方都可访问类中的变量
类和结构体的对比
- 可见度的区别:
类中成员默认为私有成员,结构体中成员默认为公有成员。
构造函数
构造函数的基本概念
构造函数是一种特殊类型的方法,在每次实例化对象时都会进行。
构造函数可以有参数,因此可以发生重载。
构造函数无返回类型,名字与类相同。
使用一个类的静态方法或使用new关键字创建对象实例时构造函数将不会运行。
new + 构造函数会创建一个新的对象。
class Entity { public: float x, y; Entity(float a, float b) //构造函数 { x = a; y = b; } void Print() { std::cout << x << "," << y << std::endl; } }; int main() { Entity e(5.0f, 9.0f); //将x初始化为5.0,y初始化为9.0 e.Print(); }
Entity为构造函数,实例化对象时每次都会初始化x,y。
删除构造函数
当希望被人只使用类而不实例化对象时,可删除构造函数。
class Log { private: Log() {}; };
class Log { public: Log() = delete; };
构造函数初始值列表
格式:
Player(const std::string& name, float x, float y) :m_name(name), X(x), Y(y) {}
- 只有成员类或基类才能显示在类或结构的初始化列表中。
- 实现初始化列表时,要确保与成员变量声明时顺序一致。
- 若不使用初始化列表,成员会构造两次,一次是默认构造函数,一次是相匹配的构造函数。
构造函数的分类
按参数分类:
- 无参构造(默认构造):
Person() {}
- 有参构造:
Person(int a) {}
按类型分类:
拷贝构造:
Person(const Person& p) {}
不能用拷贝构造函数初始化匿名对象。
普通构造
构造函数的调用
无参构造函数的调用:
Person p;
有参构造函数的调用:
- 括号调用:
Person p1(10); Person p2(P1);
- 显示调用:
Person p1 = Person(10); Person p2 = Person(p2);
会先创建匿名对象,再将匿名对象复制给p1。
- 隐式转换调用:
Person p4 = 10; //Person p4 = Person(10); Person p5 = p4; //Person p5 = Person(p4);
- 若自行创建有参构造函数,则编译器将不再提供默认构造函数,需自行创建。
- 若自行创建拷贝构造函数,则编译器将不再提供默认构造函数和有参构造函数,需自行创建。
调用的时机:
- 使用一个已经创建完毕的对象来初始化一个新对象.
Person P1(10); Person P2(P1);
- 值传递的方式给函数参数传值。
void Function(Person p1) {} void test02() { Person p; Function(p); }
- 以值方式返回局部对象
Person Function() { Person p1; return p1; //会拷贝出一个新的对象,再将新的对象返回 } void test03() { Person p = Function(); }
深拷贝与浅拷贝
class Person { public: int m_age; int* m_height; Person(int age ,int height) { m_age = age; m_height = new int(height); } ~Person() { cout << "析构函数!" << endl; if (m_height != NULL){ delete m_height; } } };
浅拷贝:直接进行赋值拷贝操作。
Person(const Person& p) { m_age = p.m_age; m_height = new int(*p.m_height); }
浅拷贝会带来的重复释放堆区内存的问题。
深拷贝:在堆区重新申请内存,再进行拷贝操作。
Person(const Person& p) { m_age = p.m_age; m_height = new int(*p.m_height); }
析构函数
- 析构函数不可以有参数,因此不可以发生重载。
- 每次销毁对象时被调用。
class Entity { public: float x, y; ~Entity() //析构函数 { x = 0; y = 0; std::cout << "destroy entity" << std::endl; } };
类的对象
类对象作为类成员
- 当类对象作为类成员时,构造时会先构造类成员,再构造自身。
- 析构时会先析构自身,再析构类成员。
成员变量和成员函数
- 成员变量和成员函数分开储存。
- 只有非静态成员变量属于类的对象。
- 静态成员变量和成员函数属于类,因为在没有对象时它们依然存在。
枚举
定义一个枚举类型
enum Type :unsigned char { A = 5, B, C, D //递增1 };
枚举默认为32位整型,可在其后加冒号再加整数类型。