一、基本类型
1、预定义类型
包含:整型、字符型、布尔型、浮点型、空类型,指针类型。
1.1整型
c++有四种整型类型:short、int、long、long long,每种都有signed(有符号,默认)、unsigned(无符号)两种分类,有符号整数既可以表示非负整数,又可以表示负整数;但是,无符号整数不能表示负数,只能表示非负整数。
在c++的实现中,每一种类型在不同系统上使用的存储位数(宽度)是不同的,其规则为:
● short至少16位
● int至少与short一样长
● long至少32位,且至少与int一样长
● long long至少64位,且至少与long一样长
1.2字符型
类型 | 大小 |
---|---|
char | 8位(即可表示28个字符) |
wchar_t | 16位 |
char16_t | 16位 |
char32_t | 32位 |
1.3布尔类型
当表达式需要一个算术值时 布尔对象和布尔文字都被隐式地提升成 int(正 如下面的例子) false 变成 0 而 true变成1,bool类型不确定大小
1.4浮点型
类型 | 大小 | 位数 |
---|---|---|
float | 32为单精度浮点数 | 7 |
double | 64位双精度浮点数 | 15/16 |
1.5空类型
关键字 void
1.6指针类型
<类型>* <指针变量>;
2、自定义数据类型
包含:数组、结构体(struct)、联合体(union)、枚举(enum)
2.1数组类型
int a[100]={1,2,3};//一维数组
int a[2][3]={{1,2,3},{4,5,6}}
2.1结构体类型
struct 名称{
数据类型 变量名1;
数据类型 变量名2;
。。。。
数据类型 变量名n;
}结构体变量名;
struct Info{
int age;
char name[32];
}info[SIZE];
2.2联合体类型
共用内存
union 名称{
数据类型 变量名1;
数据类型 变量名2;
。。。。
数据类型 变量名n;
};
2.3枚举类型
enum 枚举名{
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数]
} 枚举变量;
二、类与对象
2.1类的声明与对象的存储
#include <iostream>
using namespace std;
//类通常定义在函数外面
class Student{
public:
//类包含的变量
char *name;
int age;
float score;
//类包含的函数
void say(){
cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
};
int main(){
//创建对象
Student stu;//创建栈对象
stu.name = "小明";//创建对象以后,可以使用点号.来访问成员变量和成员函数,这和通过结构体变量来访问它的成员类似,如下所示:
stu.age = 15;
stu.score = 92.5f;
stu.say();
Student *pStu = new Student;//创建堆对象必须用指针指向匿名对象
return 0;
}
栈内存是程序自动管理的,不能使用 delete 删除在栈上创建的对象;堆内存由程序员管理,对象使用完毕后可以通过 delete 删除。在实际开发中,new 和 delete 往往成对出现,以保证及时删除不再使用的对象,防止无用内存堆积。
有了对象指针后,可以通过箭头->来访问对象的成员变量和成员函数
pStu -> name = "小明";
pStu -> age = 15;
pStu -> score = 92.5f;
pStu -> say();
class Student{
private: //私有的
char *m_name;
int m_age;
float m_score;
public:
//成员变量
char *name;
int age;
float score;
//成员函数
void say(); //函数声明 自动加入inline
};
//函数定义//需要先在类体中定义函数名称,可以再外卖重新定义实现
void Student::say(){
cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
在类体中直接定义函数时,不需要在函数名前面加上类名,因为函数属于哪一个类是不言而喻的。
但当成员函数定义在类外时,就必须在函数名前面加上类名予以限定。::被称为域解析符(也称作用域运算符或作用域限定符),用来连接类名和函数名,指明当前函数属于哪个类。
成员函数必须先在类体中作原型声明,然后在类外定义,也就是说类体的位置应在函数定义之前。
在类体中定义的成员函数会自动成为内联函数,在类体外定义的不会。当然,在类体内部定义的函数也可以加 inline 关键字,但这是多余的,因为类体内部定义的函数默认就是内联函数。
私有成员变量大都以m_开头,这是约定成俗的写法,不是语法规定的内容。以m_开头既可以一眼看出这是成员变量,又可以和成员函数中的形参名字区分开。
对象创建分别为每个对象的成员变量分配内存,但是所有对象都共享同一段函数代码。对象的大小只受成员变量的影响,和成员函数没有关系。成员函数在代码区分配内存,而不是在栈区。
对象的内存中只保留了成员变量,除此之外没有任何其他信息,程序运行时不知道 stu 的类型为 Student,也不知道它还有四个成员函数 setname()、setage()、setscore()、show(),C++ 究竟是如何通过对象调用成员函数的呢?
C++函数的编译
C++和C语言的编译方式不同。C语言中的函数在编译时名字不变,或者只是简单的加一个下划线_(不同的编译器有不同的实现),例如,func() 编译后为 func() 或 _func()。
而C++中的函数在编译时会根据它所在的命名空间、它所属的类、以及它的参数列表(也叫参数签名)等信息进行重新命名,形成一个新的函数名。这个新的函数名只有编译器知道,对用户是不可见的。对函数重命名的过程叫做名字编码(Name Mangling),是通过一种特殊的算法来实现的。
Name Mangling 的算法是可逆的,既可以通过现有函数名计算出新函数名,也可以通过新函数名逆向推演出原有函数名。Name Mangling 可以确保新函数名的唯一性,只要函数所在的命名空间、所属的类、包含的参数列表等有一个不同,最后产生的新函数名也不同。这样通过传递对象指针就完成了成员函数和成员变量的关联。这与我们从表明上看到的刚好相反,通过对象调用成员函数时,不是通过对象找函数,而是通过函数找对象。
2.2构造函数与析构函数
类体中有两个成员构造函数(Constructor)和析构函数(Destructor),构造函数的名字和类名相同,而析构函数的名字是在类名前面加一个~符号。有了构造函数在创建对象的同时为成员变量赋值。
构造函数:
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
//声明构造函数
//采用初始化列表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
//TODO:
};//:相当于赋值
Student(char *name, int age, float score);//为名称命名
~Student();
//声明普通成员函数
void show();
};
构造函数也可以重载,可以使用初始化列表,在初始化列表中成员变量的赋值顺序由它们在类中的声明顺序决定,初始化 const 成员变量的唯一方法就是使用初始化列表。
析构函数是没有参数,编译器会自动添加,也可以主动写上去.
new 创建的对象位于堆区,通过 delete 删除时才会调用析构函数;如果没有 delete,析构函数就不会被执行。
成员函数中可以使用this,并且这个类实例化以后可以使用
2.3静态变量和静态成员函数
静态变量需要在类体之外赋值,没有初始化不能使用
访问静态变量
//通过类类访问 static 成员变量
Student::m_total = 10;
//通过对象来访问 static 成员变量
Student stu("小明", 15, 92.5f);
stu.m_total = 20;
//通过对象指针来访问 static 成员变量
Student *pstu = new Student("李华", 16, 96);
pstu -> m_total = 20`
注意:static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问
普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员和静态成员函数
2.3常对象和常成员函数
const class *p = new class(params);
class const *p = new class(params);
常对象定义方法
class Student{
public:
Student(char *name, int age, float score);
void show();
//声明常成员函数
char *getname() const;
int getage() const;
float getscore() const;//常成员函数关键字
private:
char *m_name;
int m_age;
float m_score;
};
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){ }
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
//定义常成员函数
char * Student::getname() const{
return m_name;
}
int Student::getage() const{
return m_age;
}
float Student::getscore() const{
return m_score;
}
需要强调的是,必须在成员函数的声明和定义处同时加上 const 关键,只能调用常对象成员(常变量和常函数)
2.4友元
借助关键字友元(friend),可以使得其他类中的成员函数以及全局范围内的函数访问当前类的 private 成员。