【C++】类和对象(三)
一.const成员:让对象更安全
1.const关键字的作用
C++中const用来表示"常量"的意思,用来修饰变量,表示这个变量的值不可被修改。
2.const修饰普通变量
cpp
const int a=10;
此时表示"a"是常量,不可修改。
另外,const修饰的变量必须在定义时初始化,否则就会报错。
例如:

3.const修饰类成员变量
const修饰的类成员变量必须在初始化列表初始化,并且不能在构造函数体内赋值。
例如如下两种写法都是错的:


4.const修饰类成员函数
语法:
返回值 函数名(参数)const
{
...函数体
}
作用:const修饰的成员函数保证不会修改函数内对象的成员变量。
例如:

如果想让成员变量可以被const成员函数修改,可以使用"mutable"修饰变量。
例如:

使用:const对象只能调用const成员函数,非const对象可以调用任意成员函数。
例如:
cpp
class Test
{
public:
Test(int x)
:a(x)
{}
void Print1()
{
cout << "a:" << a << endl;
}
void Print2() const
{
cout << "a:" << a << endl;
}
private:
int a;
};
int main()
{
Test t1(10);
const Test t2(20);
t1.Print1();
t1.Print2();
t2.Print1();//错误,const对象只能调用const成员函数
t2.Print2();
return 0;
}
5.const成员函数和非const成员函数重载
同名const成员函数和非const成员函数可以重载,实现const对象和非const对象的不同行为。
例如:
cpp
class Test
{
public:
Test(int x)
:a(x)
{
}
void Print()
{
cout<<"普通成员函数 " << "a:" << a << endl;
}
void Print() const
{
cout << "const成员函数 " << "a:" << a << endl;
}
private:
int a;
};
int main()
{
Test t1(10);
const Test t2(20);
t1.Print(); //调用普通成员函数
t2.Print(); //调用const成员函数
return 0;
}
代码运行结果为:

二.static静态成员:类级共享与生命周期管理
1.什么是static静态成员
在C++中,"static"可以修饰类中的成员变量和成员函数,被"static"修饰的成员就被称作"静态成员变量","静态成员函数"。
2.static静态成员作用
在类中,被static修饰的成员表示该成员脱离对象实例,成为类本身的属性。
3.静态成员变量
被"static"修饰的成员变量就叫静态成员变量。
- 特性:
① 所有对象共享同一份静态成员变量。
② 必须在类外定义并初始化(除非是const static整型),因为它属于整个类,存储在静态区。
③ 不占用对象的内存空间。 - 示例:
比如我们定义了一个学生类,想统计创建了多少个学生类对象,如果使用普通成员变量,比如
cpp
class Student
{
public:
Student()
{
_count++;
}
private:
int _count;
};
这种是错误的写法,因为这样写每个学生对象都会创建一个自己的_count变量,无法统计总数。
此时就可以使用"static"关键字。
cpp
class Student
{
public:
Student()
{
_count++;
}
static int _count;//只是声明
};
int Student::_count = 0;//类外定义并初始化
int main()
{
Student s1;
Student s2;
Student s3;
cout << "学生类对象个数为:" << Student::_count;
return 0;
}
代码运行结果为:

4.静态成员函数
被"static"修饰的成员函数就叫静态成员函数。
- 特性:
① 无this指针,所以不能访问非静态成员变量/函数。
② 可通过类名或对象名调用(推荐类名::函数名)
③ 静态成员函数不能同时被const修饰,因为const修饰本质是修饰this指针,但静态成员函数不含this指针。 - 示例:
cpp
class Student
{
public:
Student()
{
_count++;
}
static void PrintCount()
{
cout << "学生类对象个数为:" << _count << endl;
}
private:
static int _count;//只是声明
};
int Student::_count = 0;//类外定义并初始化
int main()
{
Student s1;
Student s2;
Student s3;
Student::PrintCount();//通过类名::函数名调用
return 0;
}
代码运行结果为:

三.友元:突破封装的特权机制
1.为什么需要友元
C++中类的封装限制了私有成员不能在类外直接访问。
例如:
cpp
class Student
{
public:
Student(int age)
:_age(age)
{}
private:
int _age;
};
如果在类外访问,是错误的
Student s(18);
s.age = 19;//错误,私有成员类外不可直接访问
但有些情况下,类外需要访问类的私有成员,此时就需要使用友元突破封装的限制。
2.友元的概念
友元可以分为友元函数和友元类,友元可以访问当前类的私有成员和保护成员。
3.友元函数
-
定义:
友元函数不是类的成员函数,它是在类外定义的普通函数,但需要在类内使用"friend"声明。
-
特点:
① 可以访问类的私有成员和保护成员。
② 没有this指针(因为不是类的成员)。
③ 友元函数声明可以放在类的任何地方(无论放在 private、protected 还是 public,效果都一样)。
④ 一个函数可以是多个类的友元函数。
例如定义一个学生类和打印学生信息的友元函数:
cpp
class Student
{
friend void Print(const Student& s);//友元函数声明
public:
Student(string name,int age)
:_name(name),
_age(age)
{}
private:
string _name;
int _age;
};
//类外定义友元函数
void Print(const Student& s)//打印学生信息
{
cout << "学生信息为:" << s._name << " " << s._age << "岁" << endl;
}
int main()
{
Student s("张三",18);
Print(s);
return 0;
}
代码运行结果为:

4.友元类
- 定义:
一个类被声明另一个类用"friend"关键字声明,那么这个类就是另一个类的友元类。 - 特性:
① 友元类的所有成员函数都可以访问另一个类的私有成员和保护成员。
② 友元类的友元关系是单向的(A是B的友元类,B不一定是A的友元类)。
③ 友元关系不能继承(父类的友元不一定是子类的友元)。
④ 友元关系不能传递(某个类的友元的友元不一定是它的友元,比如你朋友的朋友不一定是你的朋友)。
示例代码:
cpp
class Student
{
friend class Teacher;
public:
Student(string name,int age)
:_name(name),
_age(age)
{}
private:
string _name;
int _age;
};
class Teacher
{
public:
void PrintStudent(const class Student& s)
{
cout << "学生信息为:" << s._name << " " << s._age << "岁" << endl;
}
};
int main()
{
Student s("张三",18);
Teacher t;
t.PrintStudent(s);
return 0;
}
代码运行结果为:

感谢阅读!