①、类和对象
类的定义,如下:
class Student{
public:
//成员变量
char *name;
int age;
float score;
//成员函数
void say(){
cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
};
定义一个 Student 类,类名首字母一般大写,{ } 内部包含成员变量和成员函数,类定义结束后有一个 ; ,代表类定义结束,不能省略。
Student LiHua;//创建对象:
Student allStu[50];//创建对象数组:
int a;int a[100];//有点类似于定义一个变量:
//对象指针:
Student stu;
Student *pStu = &stu;
Student *pStu = new Student;//在堆上创建对象:
注:在栈上创建对象是有名字的,如 stu;但是在堆上创建对象只是得到一个指针 pStu;只能通过指针访问成员变量。
栈内存是程序自动管理的,不能使用 delete 删除栈上的对象,堆内存是由程序员管理,可以使用 delete 删除,一般 new 和 delete 是成对出现的。
对象创建完成后和结构体类似,栈对象可以通过点号 . 访问成员变量。对象指针可以通过箭头 -> 访问类成员。
类成员函数定义在类体里,默认是内联函数 inline ,一般我们不希望过多使用内联函数,所以是将函数声明在类体,而将成员函数定义在类外,然后加上域解析符 :: ,代表函数属于当前类。例:
class Student{
public:
//成员变量
char *name;
int age;
float score;
//成员函数
void say(); //函数声明
};
//函数定义
void Student::say(){
cout<<name<<"的年龄是"<<age<<",成绩是"<<score<<endl;
}
②、类成员访问权限
C++ 通过 public、private、protected 三个关键字来控制成员变量和成员函数的访问权限,他们分别代表公有、私有、受保护的。在类的内部,所有成员都可以互相访问。在类的外部,只能通过对象访问 public 成员。例:
#include <iostream>
using namespace std;
//类的声明
class Student{
private: //私有的
char *m_name;
int m_age;
float m_score;
public: //共有的
void setname(char *name);
void setage(int age);
void setscore(float score);
void show();
};
//成员函数的定义
void Student::setname(char *name){
m_name = name;
}
void Student::setage(int age){
m_age = age;
}
void Student::setscore(float score){
m_score = score;
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
int main(void)
{
//在栈上创建对象
Student stu;
stu.setname("小明");
stu.setage(15);
stu.setscore(92.5f);
stu.show();
//在堆上创建对象
Student *pstu = new Student;
pstu -> setname("李华");
pstu -> setage(16);
pstu -> setscore(96);
pstu -> show();
return 0;
}
//运行结果:
小明的年龄是15,成绩是92.5
李华的年龄是16,成绩是96
本例是通过 public 的成员函数去访问 private 的成员变量,不能通过对象直接访问 private 成员。
注:通常是将类的声明放在头文件中,而将成员函数的定义放在源文件中。
对象的大小只是和成员变量有关,和成员函数没有关系,成员函数在代码区分配内存,而不是在堆栈区。
③、构造函数
函数名和类名相同,没有返回值,用户不能调用,而是在创建对象时自动执行。例:
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
//声明构造函数
Student(char *name, int age, float score);
//声明普通成员函数
void show();
};
//定义构造函数
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;
}
int main()
{
//创建对象时向构造函数传参
Student stu("小明", 15, 92.5f);
stu.show();
//创建对象时向构造函数传参
Student *pstu = new Student("李华", 16, 96);
pstu -> show();
return 0;
}
构造函数主要是做一些初始化的工作,像是在创建对象时给成员变量赋值,构造函数必须是 public 属性,否则无法调用。另外一旦定义了构造函数,在创建对象的时候必须调用,例如在上一个例子中,创建对象要是写成 Student stu 就是错误的。
其次,构造函数也可以重载,和普通函数重载是一样的。
④、构造函数的参数初始化表:可以在构造函数的函数体中对成员变量赋值。
例:
#include <iostream>
using namespace std;
class Student{
private:
char *m_name;
int m_age;
float m_score;
public:
Student(char *name, int age, float score);
void show();
};
//采用参数初始化表
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score)
{
//TODO:
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
int main(void){
Student stu("小明", 15, 92.5f);
stu.show();
Student *pstu = new Student("李华", 16, 96);
pstu -> show();
return 0;
}
定义构造函数时并没有在函数体中对成员变量逐一赋值,其函数体为空(当然也可以有其他语句),而是在函数首部与函数体之间添加了一个冒号 :,后面紧跟 m_name(name), m_age(age), m_score(score) 语句,这个语句的意思相当于函数体内部的m_name = name; m_age = age; m_score = score; 语句,也是赋值的意思。
析构函数是销毁对象时系统自动执行的一个进行清理工作的特殊函数 (释放内存、关闭打开的文件等),函数名称是类名前加一个 ~ 符号,并且没有参数,没有返回值,不能重载,所以一个类只有一个析构函数。如果用户没有定义,编译器会自动生成一个默认的析构函数。
⑤、this 指针是一个 const 指针,它指向当前对象,this 只能在类的内部使用,通过它可以访问当前对象的所有成员。注意:this 指针不能在 static 成员函数中使用。this 指针其实和创建对象时返回的指针是一样的,只不过不能人为地给 this 指针赋值。例:
//给 Student 类添加一个成员函数 printThis();,用来查看 this 指针的值
void Student::printThis(){
cout<<this<<endl;
}
//在 main() 函数中添加代码如下:
Student *pstu1 = new Student;
pstu1 -> printThis();
cout<<pstu1<<endl;
Student *pstu2 = new Student;
pstu2 -> printThis();
cout<<pstu2<<endl;
//运行结果:
0x7b17d8
0x7b17d8
0x7b17f0
0x7b17f0
⑥、static 成员变量是一种特殊的成员变量,它属于类,而不属于某个具体的对象,可作为多个对象的共享变量。
//static 成员变量必须在类声明的外部进行初始化,具体形式是:
type class::name = value;
type 是变量的类型,class 是类名,name 是变量名,value 是初始值。
static 变量既可以通过对象来访问,也可以通过类来访问,但是要注意访问权限。
static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,不占用对象的大小,到程序结束时才释放。
static 成员函数只能访问静态成员 (包括变量和函数)。
⑦、const 成员变量:
对于 const 成员变量,只能使用参数初始化表的方式赋值
如下面这种写法是错误的:
class Con{
private:
const int m_len;
int *m_arr;
public:
Con(int len);
};
Con::Con(int len){
m_len = len; //错误;
m_arr = new int[len];
}
const 成员函数可以使用类中的所有成员变量,但是不能修改,const 成员函数必须在声明和定义的时候,都要在函数头部的结尾处加上 const 关键字。
const 对象,一旦对象被定义为 const 后,就只能调用类的 const 成员了(包括变量和函数)例:
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
public:
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;
}
int main()
{
const Student stu("小明", 15, 90.6);
//stu.show(); //error
cout<<stu.getname()<<"的年龄是"<<stu.getage()<<",成绩是"<<stu.getscore()<<endl;
const Student *pstu = new Student("李磊", 16, 80.5);
//pstu -> show(); //error
cout<<pstu->getname()<<"的年龄是"<<pstu->getage()<<",成绩是"<<pstu->getscore()<<endl;
return 0;
}
getname()、getage()、getscore() 函数仅仅是获得变量的值,所以加了 const 限制,这是一种保险的做法。
⑧、友元函数 friend
可以借助友元函数来访问其他类中的私有成员。友元函数可以是其他类的成员函数,也可以是非成员函数。
public:
friend void show(Student *pstu); //在类中将 show() 声明为友元函数
//非成员函数
void show(Student *pstu){
//函数体;
}
//将Student类中的成员函数 show()声明为友元函数
public:
friend void Student::show(Address *addr)
void Student::show(Address *addr){
//函数体;
}
//另外还可以将一个类声明为另一个类的友元类,友元类中的所有函数都是另一个类的友元函数。
//在类中将Student类声明为友元类
public:
friend class Student;
注:友元类是单向且不能传递的,B 是 A 的友元类,不代表 A 是 B 的友元类;
B 是 A 的友元类,C 是 B 的友元类,不等于 C 是 A 的友元类。
⑨、C++中的 struct 和 class 基本是通用的,都可以包含成员变量和成员函数,只是 class 的成员默认都是 private 属性的,而 struct 的成员默认是 public 属性。在继承上也是一样的权限关系,但是 class 可以使用模板,但是 struct 不能。