内存分区
new的使用方法
int *p = new int(10);
//new int(10) 在堆区开辟一段内存,存放的数值是10,返回该数据类型的指针
delete p; //销毁内存
int * arr = new int[10];
// new int[10] 在堆区开辟一段连续内存,大小为10个int类型数据,返回该内存的首地址
delete[] p;
初始化列表
Person(): m_A(10), m_B(20) { }
Person(int a, int b): m_A(a), m_B(b) { }
静态成员
静态成员变量
- 所有对象共享一份数据
即类内的静态成员变量所有的对象都可以修改
- 类内声明,类外初始化(通过作用域运算符进行对变量进行初始化)
class Person
{
public:
static int age;
};
int Person::age = 10;
- 编译阶段就分配内存
- 静态成员变量也具有访问权限
私有权限下的静态成员变量不能直接被访问
静态成员函数
- 对于所有对象来说,静态成员函数只有一个即只占用一份内存
- 静态成员函数只能访问静态成员变量,不能访问其他变量
例:
static void test()
{
age = 100;
}
static int age;
此时正常
static void test()
{
age = 100;
a = 20;
}
static int age;
int a;
此时就会报错,因为 a 不是静态成员变量
- 静态成员函数也有访问权限
- 访问
Person p1;
p1.test(); // 通过对象来访问
Person::test(); // 因为test()函数属于全体对象,所以也可以通过作用域运算符来访问
成员变量与成员函数分开储存
只有非静态成员变量属于类的对象上
例:
class Person
{
}
Person p;
sizeof(p);
// 此时sizeof的值为1, 当定义一个空对象时,系统为其分配一字节的空间
class Person
{
int a;
}
Person p;
sizeof(p);
// a为非静态成员变量在类上,此时sizeof的值为 4
class Person
{
int a;
void test() { }
}
Person p;
sizeof(p);
// 函数不在类上,sizeof 的值为4,所占内存不发生改变
class Person
{
int a;
static int b;
}
int Person::b = 1;
Person p; sizeof(p);
// b为静态成员变量不属于类上,sizeof 的值为4,
友元
目的: 让私有属性可以被指定目标访问
关键词: friend
- 全局函数做友元
在类内声明语句
friend 数据类型 函数名(形参列表);
例:
class Person
{
friend void test();
private:
int m_a;
};
// 此时test()函数可以直接访问私有属性 m_a
- 友元类
类内声明语句
friend class 类名 ;
例:
class A
{
friend class B;
private:
int m_a;
};
// 此时类B内的成员可以直接访问类A中的私有属性
- 成员函数做友元
类内声明语句
friend 类名 :: 函数名(形参列表);
例:
class A
{
friend B::test();
private:
int m_a;
// 此时类B内的成员可以直接访问类A中的私有属性
运算符重载
加法运算符重载
目的: 实现自定义数据类型的加法
关键字:operator+
- 重载定义在类内
Person operator+ (Person &p) // 不返回 Person& 因为 temp 是临时变量,只需要temp内变量的值即可
{
Person temp;
temp.a = this->a + p.a;
temp.b = this->b + p.b;
//this指向调用重载函数的对象
return temp;
}
- 重载定义在全局
Person operator+ (const Person &p1, const Person &p2)
{
//重载定义在全局时,不能使用 this 指针了,故形参需要两个对象
Person temp;
temp.a = p1.a + p2.a;
temp.b = p1.b + p2.b;
return temp;
}
- 使用方法
Person p1;
p1.a = 10; p1.b = 20;
Person p2;
p2.a = 10; p2.b = 20;
// 重载定义在类内时
Person p3 = p1 + p2; // 等价于 Person p3 = P1.operator+(p2)
或
Peson p3 = p2 + p1; // 等价于 Person p3 = p2.operator+(p1)
注:两种形式中 p1 和 p2 的顺序不能改变,p1 + p2 是p1调用 operator+ 函数
p2 + p1 是 p2 调用 operator+ 函数
//重载定义在全局时
Person p3 = p1 +p2; /* 等价于 Person p3 = operator+(p1, p2),简化形式
必须是 p1 在 + 左边, p2 在右边
左移运算符的重载
目的: 直接输出一个类对象的内容
关键词: operator<<
- 重载定义在全局
class Person
{
friend ostream& operator<< (ostream& cout, Person &p);
public:
int a, b;
};
ostream& operator<< (ostream& cout, Person &p)// cout 和 p 不能交换位置, 若交换位置则结果为 p << cout
{
cout << "a = " << p.a << " b = " << p.b;
return cout;
}
/* cout << p 相当于 operator<< (cout, p) 返回值为 cout ,此时
cout << p << endl 为 cout << endl; */
cout << p << endl;
注:运算符重载只是使原来的运算符多了一种使用方式,它原来的使用方法依旧存在。例:加法运算符重载后依旧可以进行两个 int 类型数据的运算。
递增运算符重载
- 前置递增
MyIntage& MyIntage::operator++ ()
{
this->num++;
return *this; // 返回对象本身
}
cout << ++myInt << endl;
- 后置递增
MyIntage MyIntage::operator++ (int)
{
MyIntage temp = this->num;
this->num++;
return temp;
}
cout << myInt++ << endl;
注:(myInt++)++ 存在语法错误,不能这样使用
- 完整代码
class MyIntage
{
friend ostream& operator<< (ostream& cout, MyIntage myInt);
public:
MyIntage(int age);
//前置自增
MyIntage& operator++ ();
//后置自增
MyIntage operator++ (int);
private:
int num;
};
// 构造函数,给 num 赋初值
MyIntage::MyIntage(int age)
{
this->num = age;
}
// 前置自增
MyIntage& MyIntage::operator++ ()
{
this->num++;
return *this;
}
//后置自增
MyIntage MyIntage::operator++ (int)
{
MyIntage temp = this->num;
this->num++;
return temp;
}
/*左移运算符重载,用来输出类 MyIntage 的对象*/
ostream& operator<< (ostream& cout, MyIntage myInt)
{
cout << "num = " << myInt.num;
return cout;
}
void test()
{
MyIntage myInt(20);
cout << ++myInt << endl;
cout << myInt++ << endl;
}
int main()
{
test();
return 0;
}
继承
继承的基本语法
class 子类: 继承方式 父类
例:
class Son: public Base
{
}
继承方式
权限大小:共有继承 > 保护继承 > 私有继承
子类继承父类的成员,权限只能下降或者不变
如:
- 子类通过保护继承继承了在父类中为公共属性的成员,那么该成员在子类中的权限变为保护属性
- 子类通过保护继承继承了在父类中为保护属性的成员,那么该成员在子类中的权限依旧为保护属性
- 子类通过保护继承继承了在父类中为私有属性的成员,那么该成员在子类中的属性依旧为私有属性