1.类:类就是完成某一功能的相关数据和算法的集合
2.访问修饰符(3个)约束类成员的使用范围
private:类成员只能在类内使用
protected:类成员在类内和子类中可以使用,比private权限更大(继承)
public:类成员在类内和类外和子类中都可以使用,只要能定义对象的地方都可以使用
3.类默认private,结构体为public
类默认的继承方式private,结构体为public
4.构造函数,编译器默认给提供的.无返回值(不是void),函数名为当前的类名,无参数。函数体代码为空。
在定义对象的时候自动调用,用于初始化类成员属性.构造函数允许有多个
5.(一般手动重构)析构函数:无返回值,只允许有一个,无参数。函数名~类名
作用:用来回收成员申请的额外的空间(不是对象本身,而且要在对象被回收前先去回收,一般为通过new申请的空间)
class t
{
public:
int m_a;
int m_b;
t() //默认构造函数
{
m_a = 10;
m_b = 20;
}
t(int a,int b)//有参数的构造函数
{
m_a = a;
m_b = b;
}
~t() //析构函数
{
cout << "```````t" << endl;
}
};
int main()
{
t re;//当直接调用默认构造函数的时候注意不加括号
cout << re.m_a << " " << re.m_b << endl;//输出:10,20
t re2(100, 200);
cout << re2.m_a << " " << re2.m_b << endl;//输出100,200
return 0;;
}
一.成员变量的种类
类对象的种类:
1.栈区局部变量,遇到函数返回或者{}生命周期结束,自动回收。
2.通过new创建的变量,需要通过delete手动回收
3.全局变量:程序一开始创建就创建变量,程序退出(销毁)时候被回收,作用域为整个应用程序,可以跨文件.
4.静态全局,生命周期和全局是一样的。作用域:只能在当前文件中使用,具有文件作用域
5.静态局部变量,第一次调用包含这个对象的函数执行定义对象的代码,一直到程序结束销毁变量。 调用了多次包含该对象的函数,对象不会重新创建(和局部栈区变量不一样)
#include<iostream>
using namespace std;
class Test
{
public:
int m_a;
double m_b;
Test()
{
m_a = 10;
m_b = 110;
cout << "c" << endl;
}
Test(int a,double b)
{
m_a = a;
m_b = b;
cout << "c" << endl;
}
~Test()
{
cout << "~~~~~~c" << endl;
}
};
void show()
{
static Test te0;//静态局部变量
}
int main()
{
show();//在调用函数的时候创建变量,程序结束的时候销毁变量。
//虽然调用多次show函数,但是只创建一次变量
show();
show();
return 0;
}
6.临时变量。生命周期仅限于当行,遇到;结束。用于返回自定义类型的函数中
ctest play()
{
ctest te(100);
return te;//结束时te会被回收,返回的是临时对象
}
int mai1n()
{
ctest te7 = play();//返回的临时对象被te7接收,te7为局部变量
ctest();//临时对象,生命周期仅限于当前行,遇到;结束
return 0;
}
二.非静态成员
1.非静态类成员属性,属于对象,定义多个对象成员属性存在多份,互不影响。所占内存满足内存对齐规则
class Ctest0
{
};
class Ctest1
{
int a;
};
class Ctest2
{
int a;
double b;
};
int main()
{
cout << sizeof(Ctest0) << endl; //1,标识当前对象真是存在于内存
cout << sizeof(Ctest1) << endl;//4
cout << sizeof(Ctest2) << endl;//16,满足内存对齐规则
return 0;
}
2.类成员函数,属于这个类,不属于对象(存在与否不依赖于对象定义与否),在编译期就存在了。也就是说就算不定义对象,那么成员函数也是存在的,同时成员函数也不占对象内存。
class Ctest0
{
void aa() {};
};
class Ctest1
{
int a;
void aa() {};
};
class Ctest2
{
public:
int a;
void aa() {cout<<"SA"<<endl};
double b;
};
int main()
{
cout << sizeof(Ctest0) << endl; //1
cout << sizeof(Ctest1) << endl;//4
cout << sizeof(Ctest2) << endl;//16
Ctest2* p_te = nullptr;
p_te->aa();//输出SA,没创建对象但是可以直接调用,因为存在与否不依赖于对象定义与否
return 0;
}
注意:成员属性对于每个新定义的对象都要重新创建。而成员函数则是公用的,新定义的对象不用单独创建函数。
三.this指针和静态成员
1.this指针:当前类对象的指针,类中非静态成员函数的参数列表中,默认编译器加的一个隐藏的参数,在参数列表的第一个参数
作用:链接对象和类成员的桥梁
class Ctest
{
public:
int m_a;
void play()
{
m_b = 10;//隐式的通过this指针进行调用,相当于 this->m_a
}
};
2.静态成员函数:没有隐藏的this指针参数。导致了不能使用普通的成员(包括成员属性和函数)只能使用静态成员 .
静态的成员属性不占用对象的内存空间,不属于对象,属于类的,只有一份,多个对象共享(和成员函数相类似)。
其存在不依赖于对象,在编译期就存在了。其初始化要在类外进行格式:int Ctest::m_b=10;
静态成员在没有对象的情况下可以通过 类名::变量名调用,也可以通过对象调用。总之,静态的有没有都可以用。因为静态(属于类的)是早于对象的编译期就存在了
class Ctest
{
public:
int m_a;
static double m_b;//静态成员属性
static void play() //静态成员函数
{
m_b = 10; //静态成员函数只能调用静态成员属性
}
};
double Ctest::m_b = 22.0;//类外进行初始化
int main()
{
cout << Ctest::m_b << endl; //输出:22;不用创建对象也能调用对象,因为其编译期就存在了
Ctest re;
re.play();
cout << re.m_b << endl; //输出:10;经过调用play改为10
Ctest re2;
cout << re2.m_b << endl; //输出:10;新建的对象,但是m_b是不变的,和之前的对象共用
return 0;
}
总结:
静态变量:
关于静态数据成员的说明:
(1)通常,非静态数据成员存在于类类型的每个对象中,静态数据成员则独立于该类的任何对象,在所有对象之外单独开辟空间存储。在为对象所分配的空间中不包括静态数据成员所占的空间。
(2)如果只声明了类而未定义对象,则类的非静态数据成员是不占存储空间的,只有在定义对象时,才为对象的数据成员分配空间。但是只要在类中定义了静态数据成员,即使不定义任何对象,也为静态数据成员分配空间,它可以在尚未建立对象时就被引用。
(3)访问静态成员时同样需要遵守公有及私有访问规则。
4)静态数据成员必须在类外部定义一次(仅有一次),静态成员不能通过类构造函数进行初始化,而是在类外定义时进行初始化。定义静态数据成员的方式为:
数据成员类型 类名::静态数据成员名=初值;
(5)静态数据成员可用作默认实参,非静态数据成员不能用作默认实参,因为它的值不能独立于所属的对象而使用。
(6)有了静态数据成员,各对象之间实现了数据共享,因此可以
不使用全局变量。
静态成员函数:
静态成员函数在没有对象的情况下可以通过 类名::变量名调用,也可以通过对象调用。但是普通函数只能通过对象名来调用,不能通过类来调用。
非静态成员函数有this指针,而静态成员函数没有this指针。因此,静态成员函数不能访问本类中的非静态成员。静态成员函数就是专门为了访问静态数据成员的。