一 概述
- 按址传递对象虽然可以避免调用复制构造函数和析构函数,但是由于它得到了该对象的内存地址,可以随时修改对象的数据。所以,它实际上是破坏了按值传递的保护机制。
二 原因说明及避免办法
2.1 原因
- 比如说按值传递就像把罗浮宫的那副达芬奇的画制作一个副本,送交法国总理希拉克的官邸,这样希拉克堆该花的任何操作也不会影响到原画。不过假如希拉克亲自跑到罗浮宫去观赏原画,那么他完全可以对原画进行修改或操作
2.2 避免办法
不过我们仍然对此有解决办法,那就是用const指针来接受对象,这样就可以防止任何试图对该对象所进行的操作行为,并且保证返回一个不被修改的对象
三 修改过程(func函数)
3.1 过程
- A one——>A *const one:指针one不可修改
- A const* one——const A *const* one: 指针one指向的对象不可修改
- A* func——A *const func:返回的one指针不可修改
- A *const func——const A*const func:返回的one指针不可修改
3.2 结果
- 这样就保证了传递进来的数据不被修改
- 同时又保证了返回的数据也不会被修改
四 代码及结果输出
4.1 代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include<iostream> using namespace std; class A {
public: A() {cout << "执行构造函数,创建一个对象\n";} A(A&) {cout << "执行复制构造函数,创建该对象的副本\n";} ~A() {cout << "执行析构函数,删除该对象\n";} void set(int x){i=x;} int get()const{return i;} private: int i; }; const A *const func(const A *const one) { //one->get(); //one->set(11); //one++; return one; } int main() { A a; a.set(11);
const A *const p=func(&a); //p++; //p->set(11); cout<<"p:"<<p<<endl; cout<<"a:"<<&p<<endl; cout<<p->get()<<endl; return 0; }
|
4.2 输出结果
1 2 3 4 5
| 执行构造函数,创建一个对象 p:0x22fe30 a:0x22fe28 11 执行析构函数,删除该对象
|
4.3 说明
- 本节主要讲了const的用法
- 我们将函数的返回值和接收参数都定义为const,就可以保证函数内不可修改原始值,同时避免利用返回值对原始值进行修改,所以加上了这个const,实际上是为了实现按值传递的保护机制,同时又避免按值传递的开销,因为不用再调用复制构造函数
- 但是加const很麻烦,下一节课讲一种更简便的方法:按别名传递对象
- 有的人会问了,你不是说这个指向常量的常指针,它指向的对象是不可修改的吗?怎么a.set(11)这里又对它进行修改了呢?这是因为指向常量的常指针,只是限制我们用该指针修改它指向的对象的值,但是它并不会改变原始对象的属性。比如说,它将原来的对象a改为常量对象,它不会这么做,所以我们还可以用对象a修改自身的值,因为这个对象a,不是常量对象。但是我们不能通过p指针来修改它指向的对象a,因为const限制了它这么做