西昌城乡规划与建设局网站,WordPress小程序开发,网页升级访问更新中狼,做销售找客户的网站目录 
类  对象 
类定义 
对象的建立和使用 
构造函数(Constructor) 
析构函数(Destructor) 
拷贝构造函数 
扩展知识 
this指针 
友元函数的使用方法 
友元类的使用方法 
常数据的使用及初始化 类  对象 
什么是类#xff1f;什么是对象#xff1f;对于面向对象的…目录 
类  对象 
类定义 
对象的建立和使用 
构造函数(Constructor) 
析构函数(Destructor) 
拷贝构造函数 
扩展知识 
this指针 
友元函数的使用方法 
友元类的使用方法 
常数据的使用及初始化 类  对象 
什么是类什么是对象对于面向对象的C语言学习类和对象的理解是整个语言学习中核心的基础。通俗的理解类其实就是一个模子是一个变量类型对象就是这个类型定义出来的具体的变量就像int a;这句话int对应类a就对应对象。这样大家应该就好理解了但需要注意的是int是C的内置类型并不是真正的类。 
所以概括的讲类是对象的抽象和概括而对象是类的具体和实例。 
类定义 
在C中类是一种用户自定义的数据类型用于封装数据和相关的操作。类定义了对象的属性成员变量和行为成员函数并提供了一种实例化对象的模板。 下面是一个简单的C类定义的示例 
#include iostream// 定义一个名为Person的类
class Person {// 类的成员变量属性std::string name;int age;public:// 类的构造函数Person(std::string n, int a) {name  n;age  a;}// 类的成员函数方法void displayInfo() {std::cout  Name:   name  std::endl;std::cout  Age:   age  std::endl;}
};在上述示例中我们定义了一个名为Person的类。它包含了两个私有成员变量name和age以及一个公有成员函数displayInfo。 
注意在类中声明函数原型的方法与一般C语言的函数原型声明一样而在类外定义函数的方法则需要类名加::作用域限定符表示。 
在类的定义中通过public:、private:和protected:来分隔不同权限的成员。其中private表示私有被它声明的成员仅仅能被该类里的成员访问外界不能访问是最封闭的一种权限protected比private稍微公开一些除了类内自己的成员可以访问外它的子类也可以访问关于子类的概念我们会在后面详细展开而public声明的成员则可以被该类的任何对象访问是完全公开的数据。 
类的构造函数用于初始化对象的成员变量。在上述示例中我们定义了一个接受两个参数的构造函数并在构造函数中将参数值赋给成员变量。 
类的成员函数用于定义类的行为。在上述示例中displayInfo函数用于输出对象的属性值。 
对象的建立和使用 
1. 对象的创建 
在 C 中对象是类的实例。要创建一个对象必须先定义一个类以及使用该类的构造函数进行初始化。对象可以在栈上或堆上创建。 
a. 在栈上创建对象 
通过使用类名和变量名定义对象对象将分配在栈上并在它的作用域结束时自动销毁。例如 
#include iostream
using namespace std;class Person {
public:int age;string name;void sayHello() {cout  Hello, my name is   name  , and I am   age   years old.  endl;}
};int main() {Person p;     // 在栈上创建对象p.age  20;p.name  Alice;p.sayHello();return 0;
}b. 在堆上创建对象 
使用 new 运算符在堆上分配内存来创建对象返回指向该对象的指针。需要手动调用 delete 运算符来释放内存否则会导致内存泄漏。例如 
#include iostream
using namespace std;class Person {
public:int age;string name;void sayHello() {cout  Hello, my name is   name  , and I am   age   years old.  endl;}
};int main() {Person* p  new Person();    // 在堆上创建对象p-age  20;p-name  Alice;p-sayHello();delete p;                    // 释放内存return 0;
}2. 对象的指针 
对象的指针是指向对象的地址的指针。可以使用“-”运算符来访问对象的成员。 
例如在堆上创建对象并使用对象的指针 
#include iostream
using namespace std;class Person {
public:int age;string name;void sayHello() {cout  Hello, my name is   name  , and I am   age   years old.  endl;}
};int main() {Person* p  new Person();p-age  20;p-name  Alice;p-sayHello();delete p;return 0;
}3. 对象的引用 
对象的引用是对象的别名使用“”符号定义。可以将引用看作是一个对对象的另一种名称修改引用将直接影响到原对象。 
需要注意的是 
1. 与指针一样两者必须是同类型才可以引用。 
2. 除非做函数的返回值或形参时其余定义引用类型的同时就要初始化 
3. 引用类型并非是新建立一个对象因此也不会调用构造函数。 
例如 
#include iostream
using namespace std;class Person {
public:int age;string name;void sayHello() {cout  Hello, my name is   name  , and I am   age   years old.  endl;}
};int main() {Person p1;p1.age  20;p1.name  Alice;Person p2  p1;            // 引用p1p2.age  30;p2.sayHello();              // 输出“Hello, my name is Alice, and I am 30 years old.”p1.sayHello();              // 输出“Hello, my name is Alice, and I am 30 years old.”return 0;
}这就是对象的建立和使用。可以通过创建对象、使用对象的指针或引用来访问对象的成员和方法。 
构造函数(Constructor) 
构造函数Constructor是一种特殊的成员函数用于在创建对象时初始化对象的成员变量。构造函数的名称与类名相同没有返回类型包括void并且不能被直接调用。 
构造函数在以下情况下被调用 
在创建对象时自动调用构造函数进行初始化。使用 new 运算符在堆上创建对象时需要显式调用构造函数进行初始化。当对象作为参数传递给函数时会调用复制构造函数进行初始化。 
构造函数可以有多个重载版本允许根据不同的参数列表对对象进行不同的初始化。 
以下是一个示例展示了如何定义和使用构造函数 
#include iostream
#include cstringusing namespace std;class Student {
private:int num;        // 学号char name[100]; // 姓名int score;      // 成绩public:Student(int n, const char* str, int s);   // 构造函数void print();                       // 打印学生信息void set(int n, const char* str, int s);  // 设置学生信息
};Student::Student(int n, const char* str, int s) {num  n;strcpy_s(name, str);score  s;cout  Constructor  endl;
}void Student::print() {cout  num     name     score  endl;
}void Student::set(int n, const char* str, int s) {num  n;strcpy_s(name, str);score  s;
}int main() {Student A(100, dotcpp, 11);A.print();return 0;
}输出 
Constructor
100 dotcpp 11 
这段代码定义了一个 Student 类包括三个私有属性和三个公有方法。 
其中构造函数 Student(int n, char *str, int s) 用于初始化学生对象的属性其中 n 是学号str 是姓名s 是成绩。在构造函数中使用 strcpy() 函数将姓名复制到类的 name 成员变量中。构造函数中还输出了一条语句用于提示当对象创建时构造函数被调用了。 
print() 方法用于打印学生的学号、姓名和成绩然后返回一个整数。 
set(int n, const char* str, int s)方法用于设置学生对象的学号、姓名和成绩。在该方法中同样使用 strcpy_s() 函数将姓名复制到成员变量中。 
在 main() 函数中创建了一个名为 A 的 Student 对象并通过构造函数传入了学号、姓名和成绩。然后调用 print() 方法打印学生信息最后结束程序。 
需要注意的是在类内部定义方法时不需要再加上类名作为前缀。而在类外部定义方法时需要加上类名作为前缀指明该方法是属于哪个类的。 
析构函数(Destructor) 
析构函数是一个特殊的成员函数它在对象被销毁时自动调用。它的名称与类名相同前面加上一个波浪线~作为前缀没有参数和返回值。析构函数主要用于释放对象占用的资源例如释放动态分配的内存或关闭打开的文件等。 
析构函数的定义方式与普通成员函数相似在类的声明中声明它并在类的定义中实现它。例如 
class MyClass {
public:// 构造函数MyClass();// 析构函数~MyClass();
};MyClass::MyClass() {// 构造函数的实现
}MyClass::~MyClass() {// 析构函数的实现
}当对象被销毁时例如超出其作用域、delete 运算符被调用或程序执行结束析构函数会自动调用。在调用析构函数之前对象的成员变量已经被自动销毁析构函数主要负责清理其他资源并执行必要的清理操作。 
需要注意的是如果没有显式定义析构函数编译器会生成默认的析构函数。默认的析构函数为空不执行任何操作。对于大多数情况下可以依赖编译器生成的默认析构函数。但如果类中有需要释放的资源如动态分配的内存则需要显式定义析构函数来进行资源的释放。 
以下是一个示例展示了如何在析构函数中释放动态分配的内存 
#include iostreamclass DynamicArray {
private:int* arr;int size;public:DynamicArray(int s);~DynamicArray();
};DynamicArray::DynamicArray(int s) {size  s;arr  new int[size];std::cout  DynamicArray 构造函数  std::endl;
}DynamicArray::~DynamicArray() {delete[] arr;std::cout  DynamicArray 析构函数  std::endl;
}int main() {DynamicArray array(5);return 0;
}在上面的示例中DynamicArray 类包含一个动态分配的整数数组 arr 和数组的大小 size。在构造函数中使用 new 运算符动态分配了一块内存空间并将指针赋值给成员变量 arr。在析构函数中使用 delete[] 运算符释放了之前分配的内存空间。 
当对象超出作用域时析构函数会自动调用释放动态分配的内存。输出结果将显示构造函数和析构函数的调用顺序。 
总之析构函数在对象销毁时执行必要的清理操作是重要的资源管理工具之一。它的设计和实现应该与类的构造函数相对应确保资源的正确释放和清理。 
拷贝构造函数 
拷贝构造函数是一种特殊的构造函数用于创建一个新对象该对象是已有对象的副本。它接受一个同类对象作为参数并使用该对象的值来初始化新对象。拷贝构造函数通常用于以下场景 
当使用一个对象初始化另一个对象时例如通过赋值操作、传递参数给函数、从函数返回对象等。当对象按值传递给函数或从函数返回时会调用拷贝构造函数创建对象的副本。 
拷贝构造函数的定义方式与普通构造函数的语法相似但是参数是对同类的引用。例如 
class MyClass {
public:// 拷贝构造函数MyClass(const MyClass other);// 其他成员函数和构造函数
};在拷贝构造函数中我们通常需要执行深拷贝deep copy以确保新对象与原始对象是独立的而不是共享相同的资源。这意味着拷贝构造函数应该复制所有的成员变量包括动态分配的资源如堆上的内存。 
以下是一个示例展示了如何定义和使用拷贝构造函数 
#include iostream
#include cstringclass String {
private:char* data;int length;public:// 构造函数String(const char* str);// 拷贝构造函数String(const String other);// 析构函数~String();// 其他成员函数和操作符重载
};String::String(const char* str) {length  strlen(str);data  new char[length  1];strcpy_s(data, length  1, str);std::cout  构造函数  std::endl;
}String::String(const String other) {length  other.length;data  new char[length  1];strcpy_s(data, length  1, other.data);std::cout  复制构造函数  std::endl;
}String::~String() {delete[] data;std::cout  析构函数  std::endl;
}int main() {String str1(Hello);String str2  str1;  // 使用拷贝构造函数创建对象副本return 0;
}在上面的示例中String 类表示一个动态分配的字符串。在构造函数中我们通过将传入的字符串复制到新分配的内存中来初始化对象。在拷贝构造函数中我们使用参数对象的值来初始化新对象。通过在 main() 函数中创建对象 str1 和 str2并复制 str1 给 str2我们可以看到构造函数和拷贝构造函数的调用顺序。 
需要注意的是如果没有显式定义拷贝构造函数编译器会生成默认的拷贝构造函数。默认的拷贝构造函数会逐个复制每个成员变量但对于动态分配的资源它只会进行浅拷贝shallow copy即复制指针而不是复制指针所指向的内容。这可能导致多个对象共享同一个资源从而引发潜在的问题。因此如果类中有动态分配的资源通常需要显式定义拷贝构造函数来执行深拷贝。 
总结起来拷贝构造函数用于创建对象的副本并确保副本对象是独立的。它在对象拷贝和传递过程中扮演着重要角色特别是当类中包含动态分配的资源时。 
扩展知识 
在C中浅拷贝与深拷贝的比较 
1、默认拷贝构造函数 
默认拷贝构造函数会进行浅拷贝。它会简单地按位复制对象的数据成员包括指针成员的地址。浅拷贝创建的对象和原始对象共享指针成员所指向的资源。 
2、自定义拷贝构造函数或重载赋值运算符 
如果需要进行深拷贝我们必须自定义拷贝构造函数或重载赋值运算符。在自定义的拷贝构造函数或赋值运算符中我们需要对指针成员进行动态分配内存并复制原始对象的资源。 
下面是一些比较浅拷贝和深拷贝的关键点 
对象的生命周期浅拷贝创建的对象和原始对象共享资源当其中一个对象被销毁时资源可能会被提前释放导致其他对象无法访问。而深拷贝创建的对象独立于原始对象每个对象有自己的资源副本它们的生命周期是相互独立的。资源管理浅拷贝可能会导致资源泄漏或重复释放因为多个对象共享相同的资源。而深拷贝通过复制资源的内容来避免这些问题每个对象都有自己的资源副本可以独立管理和释放资源。对象之间的关系浅拷贝会导致多个对象之间存在强耦合关系一个对象的修改会影响其他对象。而深拷贝创建的对象相互独立修改一个对象不会影响其他对象它们之间没有耦合关系。深度嵌套对象的处理在涉及深度嵌套对象的情况下浅拷贝可能无法正确处理内部对象的拷贝。而深拷贝可以递归地复制内部对象确保每个对象都有独立的资源副本。 
总的来说在C中浅拷贝和深拷贝的选择取决于对象的特性、资源的复杂性以及对对象之间关系的需求。如果对象包含指针成员变量指向的动态分配资源通常需要使用深拷贝以确保每个对象都有独立的资源副本。而对于简单的值类型成员变量和不涉及资源管理的情况浅拷贝可能是更简单和高效的选择。 
下面是一个示例它演示了如何在一个类中使用浅拷贝和深拷贝来管理多个资源。 
#include iostream
#include cstringclass Person {
private:char* name;int age;double* scores;public:// 默认构造函数Person(const char* n, int a, double* s) : age(a) {// 分配内存并复制名称name  new char[strlen(n)  1];strcpy_s(name, strlen(n)  1, n);// 分配内存并复制成绩scores  new double[3];memcpy(scores, s, sizeof(double) * 3);}// 拷贝构造函数Person(const Person other) : age(other.age) {// 分配新内存并复制名称name  new char[strlen(other.name)  1];strcpy_s(name, strlen(other.name)  1, other.name);// 分配新内存并复制成绩scores  new double[3];memcpy(scores, other.scores, sizeof(double) * 3);}// 析构函数~Person() {// 释放内存delete[] name;delete[] scores;}// 打印信息void printInfo() {std::cout  姓名  name  std::endl;std::cout  年龄  age  std::endl;std::cout  成绩;for (int i  0; i  3; i) {std::cout  scores[i]   ;}std::cout  std::endl;}// 获取成绩数组double* getScores() const {return scores;}// 修改成绩数组void setScores(double* s) {memcpy(scores, s, sizeof(double) * 3);}
};int main() {double scores[]  { 80.0, 90.0, 95.0 };Person p1(张三, 20, scores);Person p2  p1;// 浅拷贝p1.printInfo(); //输出成绩80 90 95p2.printInfo(); //输出成绩80 90 95// 修改p2的成绩double newScores[]  { 85.0, 92.0, 98.0 };p2.setScores(newScores);p1.printInfo(); // 输出成绩80 90 95p2.printInfo(); // 输出成绩85 92 98return 0;
}在上面的代码示例中Person类包含了多个资源包括一个字符数组名称、一个整数年龄和一个双精度浮点型数组成绩。它实现了一个默认构造函数来分配内存并复制这些资源以及一个浅拷贝构造函数和深拷贝构造函数。 
在浅拷贝构造函数中我们简单地复制指针这样新对象和原始对象将共享相同的资源。在深拷贝构造函数中我们为每个资源分配新内存并将原始对象的资源复制到新内存中以确保每个对象都有独立的资源副本。 
在main()函数中我们创建了两个Person对象p1和p2并进行了浅拷贝。然后我们修改了p2的一个成绩而p1也受到了影响因为它们共享相同的成绩数组。 
这说明了浅拷贝的一个缺点当多个对象共享相同的资源时修改任何一个对象都会影响其他对象。因此在处理包含多个资源的对象时需要慎重考虑浅拷贝和深拷贝之间的选择以确保对象的行为符合预期并避免意外的错误。 
this指针 
C中的this指针是一个隐含的指针它指向当前对象的地址。在成员函数中可以使用this指针来访问该对象的成员变量和成员函数。 
在类定义中成员函数的声明中并没有this指针但在实现时会隐含加上。例如 
class Person {
public:void setName(const char* name);const char* getName() const;private:char* m_name;
};void Person::setName(const char* name) {this-m_name  new char[strlen(name)  1];strcpy(this-m_name, name);
}const char* Person::getName() const {return this-m_name;
}在上面的代码中成员函数setName()和getName()中均使用了this指针来访问m_name成员变量。例如在setName()函数中我们使用了this-m_name来表示当前对象的m_name成员变量。 
在实际使用中this指针通常用于解决命名冲突问题。例如在下面的代码中我们定义了一个成员变量和一个函数参数同名都为name的情况 
#define _CRT_SECURE_NO_WARNINGS#include iostreamclass Person {
public:void setName(const char* name);const char* getName() const;private:char* name;
};void Person::setName(const char* name) {this-name  new char[strlen(name)  1];strcpy(this-name, name);
}const char* Person::getName() const {return this-name;
}int main() {Person p;const char* name  John;p.setName(name);std::cout  p.getName()  std::endl;return 0;
}在上面的代码中我们使用了this指针来区分成员变量name和参数name。例如在setName()函数中我们使用了this-name来表示当前对象的name成员变量。 
总之this指针是C中一个非常重要的概念它可以帮助我们访问当前对象的成员变量和成员函数并解决命名冲突问题。 
友元函数的使用方法 
在C中友元函数是一种特殊的函数它能够访问其它类的私有成员和保护成员。通常情况下只有类的成员函数和派生类才能访问类的私有成员和保护成员。但是在某些情况下如果我们需要外部函数或者类来访问类的私有成员和保护成员时就可以使用友元函数。 
友元函数并不是类的成员函数它只是被声明为友元的普通函数但是其声明方式与类的成员函数类似将该函数的声明放在类定义的public、protected、private之外并且在函数名前加上关键字friend如下所示 
class MyClass {
public:friend void friendFunction();
};void friendFunction() {// 可以访问MyClass的私有成员和保护成员
}friendFunction被声明为MyClass的友元函数因此它可以访问MyClass的私有成员和保护成员。友元函数可以在类内或类外定义但需要注意的是在定义友元函数时不需要再次使用friend关键字。 
另外一个类可以有多个友元函数也可以是多个类的友元函数。例如 
class MyClass2;class MyClass1 {
public:friend void friendFunction1(MyClass1 obj); // MyClass1的友元函数friend void friendFunction2(MyClass1 obj, MyClass2 obj2); // MyClass1和MyClass2的友元函数private:int m_privateData;
};class MyClass2 {
public:friend void friendFunction2(MyClass1 obj, MyClass2 obj2); // MyClass1和MyClass2的友元函数private:int m_privateData;
};void friendFunction1(MyClass1 obj) {std::cout  friendFunction1 访问 MyClass1 的私有数据   obj.m_privateData  std::endl;
}void friendFunction2(MyClass1 obj, MyClass2 obj2) {std::cout  friendFunction2 访问 MyClass1 的私有数据   obj.m_privateData  std::endl;std::cout  friendFunction2 访问 MyClass2 的私有数据  obj2.m_privateData  std::endl;
}在上面的代码中MyClass1和MyClass2都声明了一个私有成员变量m_privateData。friendFunction1是MyClass1的友元函数可以访问MyClass1的私有成员friendFunction2是MyClass1和MyClass2的友元函数可以访问两个类的私有成员。 
需要注意的是友元函数并不属于类的成员函数因此它不能使用this指针来访问对象的成员。但是可以通过参数传递对象的引用或指针来访问对象的成员。 
友元类的使用方法 
在C中友元类是一种特殊的类它可以访问其它类的私有成员和保护成员。与友元函数类似通常情况下只有类的成员函数和派生类才能访问类的私有成员和保护成员。但是在某些情况下如果我们需要外部类来访问类的私有成员和保护成员时就可以使用友元类。 
友元类是通过在类定义中将另一个类声明为友元来实现的。被声明为友元的类可以访问该类的私有成员和保护成员。友元类的声明方式如下 
class MyClass {friend class FriendClass;
};以上代码将FriendClass声明为MyClass的友元类。这意味着FriendClass可以访问MyClass的私有成员和保护成员。需要注意的是友元关系是单向的即如果将FriendClass声明为MyClass的友元类则MyClass不能访问FriendClass的私有成员和保护成员。 
友元类的使用方法与友元函数类似但是需要注意以下几点 
友元类只能在类定义中声明不能在类的成员函数或类外声明。友元类的访问权限不受访问控制修饰符的限制即无论FriendClass是public、protected还是private都可以访问MyClass的私有成员和保护成员。 
下面是一个使用友元类的例子 
#include iostreamclass MyClass {
public:MyClass(int data) : m_data(data) {}private:int m_data;friend class FriendClass; // 友元类声明
};class FriendClass {
public:void printData(const MyClass obj) {std::cout  Friend Class访问My Class的私人数据   obj.m_data  std::endl;}
};int main() {MyClass obj(100);FriendClass fc;fc.printData(obj); // 输出Friend Class访问My Class的私人数据 100return 0;
}在上面的代码中MyClass声明了一个私有成员变量m_data并将FriendClass声明为友元类。FriendClass可以访问MyClass的私有成员因此在printData函数中可以输出MyClass对象的私有成员m_data。在主函数中创建了一个MyClass对象和一个FriendClass对象并通过FriendClass的printData函数访问了MyClass对象的私有成员。 
需要注意的是虽然友元类可以访问类的私有成员和保护成员但过度使用友元类可能会破坏封装性和安全性因此应该谨慎使用。 
常数据的使用及初始化 
1、常数据成员 
常数据成员是指在类中声明为常量的数据成员它们的值在对象创建后不能再被修改。常数据成员可以用来表示对象的特定属性或限制其状态的不可变性。 
在类中声明常数据成员时需要使用const关键字进行修饰。常数据成员必须在对象的构造函数初始化列表中进行初始化因为它们的值在对象构造时就确定了并且不能在构造函数内部进行修改。使用的格式如下 
数据类型 const 数据成员名;或const 数据类型 数据成员名; 
另外有一个特殊情况如果成员是static类型即静态常数据成员因为是静态的属性初始化则需在类外进行初始化。  
例如下面是一个表示圆的类其中pi是一个常数据成员 
class Circle {
private:const double pi  3.14159;double radius;public:Circle(double r) : radius(r) {}double calculateArea() const {return pi * radius * radius;}
};在上面的代码中pi被声明为常数据成员并在构造函数初始化列表中初始化。它的值在对象创建后不能再被修改。 
2、常成员函数 
常成员函数是指在类中声明为常量的成员函数它们在函数体内不能修改对象的非常数据成员。常成员函数可以用来提取对象的信息或执行一些只读操作保证不会对对象的状态造成改变。 
声明常成员函数时在函数声明的末尾使用const关键字进行修饰。常成员函数被称为常函数它们可以被常对象调用。定义格式如下 
返回类型 函数名(形参表列) const; 
需要注意 
(1)常成员函数的定义和声明部分都要包含const 
(2)常成员函数只能调用常成员函数而不能调用非常成员函数访问但不可以更改非常成员变量。 
例如以下是一个表示矩形的类其中getArea()是一个常成员函数 
class Rectangle {
private:double length;double width;public:Rectangle(double l, double w) : length(l), width(w) {}double getArea() const {return length * width;}
};在上面的代码中getArea()被声明为常成员函数并在函数声明末尾使用了const关键字。这表明该函数不会对对象的状态进行修改。 
3、常对象 
常对象是指通过将对象声明为常量来限制其状态的对象常对象的数据成员在对象创建后不能再被修改。常对象只能调用常成员函数而不能调用非常成员函数。 
创建常对象时在对象的类型前加上const关键字即可。常对象的值在创建后不能再被修改。定义格式如下 
类型 const 对象名;或const 类型 对象名; 
需要注意的是常对象不可以访问类中的非常成员函数只能访问常成员函数。 
例如以下是一个使用常对象的示例 
int main() {const Rectangle r(10, 5); // 创建一个常对象double area  r.getArea(); // 可以调用常成员函数// r.length  20; // 错误常对象的数据成员不可修改return 0;
}在上面的代码中r是一个常对象它的值在创建后不能再被修改。因此尝试修改r的数据成员会导致编译错误。 
通过使用常数据成员、常成员函数和常对象可以确保对象的状态不会被修改并提供更安全和可靠的代码。常数据成员和常成员函数的使用可以在类内部和外部限制对对象的修改而常对象可以确保在特定情况下对象的状态不会被改变。