1. const对象
1.概念:在 C++ 中,const 用于定义常量对象,一旦对象被初始化,其值就不能再改变。因为 const 对象只能被创建、撤销和只读访问,写操作是不允许的。
2.根本利用
- #include <iostream>
- #include <cstring>
- namespace myspace1
- {
- using std::endl;
- using std::cout;
- using std::cin;
- using std::string;
- }
- using namespace myspace1;
- class Person
- {
- public:
- Person() :_age(0), _name(new char[strlen("张三") + 1])
- {
- cout << "无参构造" << endl;
- strcpy(_name, "张三");
- }
- Person(int age, const char* name) :_age(age), _name(new char[strlen(name) + 1])
- {
- cout << "有参构造" << endl;
- strcpy(_name, name);
- }
- void setAge(int age)
- {
- _age = age;
- }
- void print()
- {
- cout << "age=" << _age << endl;
- cout << "name=" << _name << endl;
- }
- //const成员函数,不能修改对象的数据成员
- void print() const
- {
- cout << "age=" << _age << endl;
- cout << "name=" << _name << endl;
- }
- ~Person()
- {
- delete[] _name;
- cout << "析构函数" << endl;
- }
- private:
- int _age;
- char* _name;
- };
- int main(void)
- {
- //普通对象
- Person p1(1,"张大");
- p1.print();
- p1.setAge(10);
- p1.print();
- //const 对象只能被创建、撤销和只读访问,写操作是不允许的
- const Person p2(2, "张二");
- //p2.setAge(20) //不允许
- //p2.print(); //不允许
- p2.print(); //调用的是void print() const
- return 0;
- }
复制代码
3.总结
const对象与const成员函数的规则:
(1)当类中有const成员函数和非const成员函数重载时,const对象会调用const成员函数,非const对象会调用非const成员函数;
(2)当类中只有一个const成员函数时,无论const对象还黑白const对象都可以调用这个版本;
(3)当类中只有一个非const成员函数时,const对象就不能调用非const版本。
发起:如果一个成员函数中确定不会修改数据成员,就把它定义为const成员函数。
2. 指向对象的指针
- int main(void)
- {
- //在栈上开辟空间
- Person p1(1, "一号");
- Person* p2 = &p1; //指向p1的指针;
- Person* p3 = nullptr; //空指针;
- //在堆上开辟空间
- Person* p4 = new Person(2, "二号");
- delete p4;
- p4 = nullptr;
- Person* p5 = new Person();
- p5->setAge(20);
- p5->print();
- (*p5).setAge(30);
- (*p5).print();
- delete p5;
- p5 = nullptr;
- return 0;
- }
复制代码 3. 对象数组
- #include <iostream>
- #include <cstring>
- namespace myspace1
- {
- using std::endl;
- using std::cout;
- using std::cin;
- using std::string;
- }
- using namespace myspace1;
- class Person
- {
- public:
- Person() :_age(0), _name(new char[strlen("张三") + 1])
- {
- cout << "无参构造" << endl;
- strcpy(_name, "张三");
- }
- Person(int age, const char* name) :_age(age), _name(new char[strlen(name) + 1])
- {
- cout << "有参构造" << endl;
- strcpy(_name, name);
- }
- void setAge(int age)
- {
- _age = age;
- }
- void print()
- {
- cout << "age=" << _age << endl;
- cout << "name=" << _name << endl;
- }
- //const成员函数,不能修改对象的数据成员
- void print() const
- {
- cout << "age=" << _age << endl;
- cout << "name=" << _name << endl;
- }
- ~Person()
- {
- delete[] _name;
- cout << "析构函数" << endl;
- }
- public:
- int _age;
- char* _name;
- };
- int main(void)
- {
- // 方式一:使用无参/默认构造函数创建对象数组
- cout << "使用默认构造函数创建对象数组:" << endl;
- Person p1[3];
- for (int i = 0; i < 3; i++) {
- p1[i].print();
- }
- // 方式二:使用有参构造函数初始化对象数组
- cout << "使用有参构造函数初始化对象数组:" << endl;
- Person p2[3] = {
- Person(20, "李四"),
- Person(21, "王五"),
- Person(22, "赵六")
- };
- for (int i = 0; i < 3; ++i) {
- p2[i].print();
- }
- // 方式三:动态分配对象数组
- cout << "动态分配对象数组:" << endl;
- Person* p3 = new Person[2];
- p3[0].setAge(25);
- strcpy(p3[0]._name, "孙七");
- p3[1].setAge(26);
- strcpy(p3[1]._name, "周八");
- for (int i = 0; i < 2; ++i) {
- p3[i].print();
- }
- // 释放动态分配的内存
- delete[] p3;
- return 0;
- }
复制代码 4. c++中const常见用法总结
4.1 修饰常量
- //只有读权限,没有写权限
- const int a = 10; //==int const a=10;
- //a = 20; 不可以修改
复制代码 4.2 修饰指针
- int main(void)
- {
-
- int a = 10;
- int b = 20;
- //1.指向常量的指针
- const int* p1 = &a; //==int const* p1 = &a;
- //*p1 = 100; 不可以为通过指针修改a的值;
- p1 = &b; //可以修改指针p1的指向
- //2.常量指针;可以通过指针修改变量的值,但是指针的指向不可以变;
- int* const p2 = &a;
- *p2 = 20;
- //p2 = &b; 错误
- //3.指向常量的常量指针:指针的指向和所指向的值都不能改变
- const int* const p3 = &a;
- // *p3 = 20; // 错误,不能通过指针修改所指向的值
- // p3 = &b; // 错误,不能改变指针的指向
- return 0;
- }
复制代码 4.3 修饰函数参数
const 用于修饰函数参数时,能够包管在函数内部不会修改该参数的值。
- void fun(const int a)
- {
- //a = 100; 错误
- cout << "a=" <<a<< endl;
- }
- int main(void)
- {
- int a = 10;
- fun(a);
- return 0;
- }
复制代码 4.4 修饰函数返回值
const 修饰函数返回值时,表明返回值是一个常量,不能被修改。
- //const 修饰函数返回值时,表明返回值是一个常量,不能被修改。
- int const fun()
- {
-
- int a = 10;
- return a;
- }
- int main(void)
- {
- //fun() = 100; 错误,不可以修改
- return 0;
- }
复制代码 4.5 修饰成员函数
const 修饰类的成员函数时,表明该成员函数不会修改对象的状态
- class MyClass {
- private:
- int _value;
- public:
- MyClass(int val) : _value(val) {}
- // 常量成员函数
- int getValue() const {
- // value = 20; // 错误,不能在常量成员函数中修改成员变量
- return _value;
- }
- };
复制代码 4.6 const对象
const 对象是指那些一经创建,其状态(即成员变量的值)就不能被修改的对象
- class MyClass {
- public:
- int _value;
- MyClass(int v) : _value(v) {}
- };
- int main() {
- const MyClass obj(10);
- // obj.value = 20; // 错误,不能修改 const 对象的成员变量
- cout << "Value: " << obj._value << endl;
- return 0;
- }
复制代码 5. 赋值运算符函数(增补)
5.1 概念
- Point pt1(1, 2), pt2(3, 4);
- pt1 = pt2;//赋值操作
复制代码 在执行 pt1 = pt2; 该语句时, pt1 与 pt2 都存在,以是不存在对象的构造,这要与 Point pt2 =pt1; 语句区分开,这是差别的。以是当 = 作用于对象时,需要调用的是赋值运算符函数。
格式:
- 类名& operator=(const 类名 &)
复制代码- class Point {
- private:
- int _ix;
- int _iy;
- public:
- Point(int x = 0, int y = 0) : _ix(x), _iy(y) {}
- //默认赋值运算符重载函数
- Point& operator=(const Point& rhs)
- {
-
- _ix = rhs._ix;
- _iy = rhs._iy;
-
- return *this;
- }
- void print() const {
- cout << "(" << _ix << ", " << _iy << ")" <<endl;
- }
- };
- int main() {
- Point p1(1, 2);
- Point p2(3, 4);
- p2 = p1;
- p2.print();
- return 0;
- }
复制代码 5.2 默认赋值运算符函数局限
(1)当类中包含指针数据成员且该指针指向堆上分配的内存时,默认的赋值运算符函数(编译器主动生成的)就无法满意需求,这可能会导致浅拷贝题目,进而引发内存泄漏或悬空指针等错误。
(2)默认的赋值运算符执行的是浅拷贝,也就是只复制指针的值,而不复制指针所指向的内存。这会造成两个对象的指针成员指向同一块内存,当此中一个对象被销毁时,它会释放这块内存,而另一个对象的指针就会变成悬空指针。另外,如果两个对象都实验释放同一块内存,会导致重复释放,引发未定义行为。
- class Person
- {
- public:
- //构造函数
- Person(const int* age) :_age(new int(*age))
- {
- cout << "构造函数" << endl;
- }
- //打印函数
- void print()const
- {
- cout << "age=" << *_age << endl;
- }
- //析构函数
- ~Person()
- {
- delete _age;
- cout << "析构函数" << endl;
- }
- private:
- int* _age;
- };
- int main(void)
- {
- int age1 = 20;
- int age2 = 30;
- Person p1(&age1);
- p1.print();
- Person p2(&age2);
- p2.print();
- p2 = p1;
- return 0;
- }
复制代码 题目分析:
当执行 p2 = p1; 时,会调用编译器主动生成的默认赋值运算符。默认赋值运算符执行的是浅拷贝,即只复制指针的值,而不复制指针所指向的内存。这会导致 p1 和 p2 的 _age 指针指向同一块内存。由于浅拷贝,当 p2 对象被销毁时,会释放 _age 所指向的内存。此时,p1 的 _age 指针就会变成悬空指针。当 p1 对象被销毁时,再次释放同一块内存,会导致重复释放,引发未定义行为。
5.3 解决办法
为相识决浅拷贝的题目,需要自定义赋值运算符函数,实现深拷贝。深拷贝会为新对象分配新的内存,并将原对象的数据复制到新的内存中。
- class Person
- {
- public:
- //构造函数
- Person(const int* age) :_age(new int(*age))
- {
- cout << "构造函数" << endl;
- }
- //打印函数
- void print()const
- {
- cout << "age=" << *_age << endl;
- }
- //自定义赋值运算符函数
- Person& operator=(const Person& rhs)
- {
- //自我赋值检查
- if (this != &rhs) {
- //释放当前_age空间;
- delete _age;
- _age = nullptr;
- _age = new int(*rhs._age);
-
- }
- return *this;
- }
- //析构函数
- ~Person()
- {
- delete _age;
- cout << "析构函数" << endl;
- }
- private:
- int* _age;
- };
- int main(void)
- {
- int age1 = 20;
- int age2 = 30;
- Person p1(&age1);
- p1.print();
- Person p2(&age2);
- p2.print();
- p2 = p1;
- return 0;
- }
复制代码 若你有自行定义某些特殊成员函数,编译器会为类主动生成以下 6 个默认函数:
- 默认构造函数
- 析构函数
- 拷贝构造函数
- 拷贝赋值运算符
- 移动构造函数(C++11 及以后)
- 移动赋值运算符(C++11 及以后)
注意:拷贝构造函数、赋值运算符函数、析构函数,如果需要手动定义此中的一个,那么另外两个也需要手动定义。 三合成原则
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |