文章目录
- 1. const成员
- 2.取地址及const取地址操作符重载
- 3. 再谈构造函数
- 3.1构造函数体赋值
- 3.2初始化列表
1. const成员
将const修饰的成员函数称为const成员函数。
const修饰类成员函数,实际修饰该成员函数的隐含地this指针,表明在该成员函数中不能对类的任何成员进行修改。
#include<stdio.h>
#include<iostream>
using namespace std;
class A
{
public:void Print(){cout << _a << endl;}
private:int _a = 10;
};
//
int main()
{A aa;aa.Print();return 0;
}
const A aa;//此时调用不动,编译报错
出现权限放大问题。传参时&aa的类型是什么?const A*,指向的内容不能改变。
传到A*,出现权限放大。只能改变this指针的类型,但无法改变this指针的类型。
隐含的参数不能自己去改,所以只能用间接的方式:
void Print() const//const修饰*this,this指针的类型变成了const A*
void Print(A* const this)//const修饰this指针,但this指针本身不能改变。const没有影响
只要内部不改变成员变量都应该用const修饰一下。
void Add(int x)const
{_a+=x;
}//不能用const修饰
内部不改变成员变量的成员函数,最好加上const,const对象和普通对象都可以调用。
流插入和流提取能不能用const?
- 他们都不是成员函数,不能。
声明和定义都要加const。
2.取地址及const取地址操作符重载
不写编译器会自己定义一个。
针对const版本的重载。const不写版本也会自动生成。
除了赋值也有一个运算符可以不重载直接用,取地址。因为是默认成员函数。
//不想让类取到地址。
const A* operator&() const
{//return this;return nullptr;
}
A* operator&()
{//return this;return (A*)0x01;//要强转因为整形不能传给指针
}
class Array
{
public:int& operator[](int i){assert(i < 10);return _a[i];//返回第i个数据}const int& operator[](int i) const//第一个const:返回值类型{assert(i < 10);return _a[i];}//他们俩构成函数重载,因为参数不同
private:int _a[10];int _size;
};
int main()
{Array a;//自定义类型for (int i = 0; i < 10;++i){a[i] = i;//变成一个函数调用,防越界}for (int i=0; i < 10;++i){cout << a[i] << " ";}cout << endl;return 0;
}
不是说一个类只能提供const版本
3. 再谈构造函数
3.1构造函数体赋值
C++在构造函数中还加了初始化列表。
成员变量现在有两种初始化方式,
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}//函数体内的赋值初始化
private:int _year;int _month;int _day;
};
虽然上述函数调用以后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化。构造函数体中的语句只能称之为赋初值,而不能称作初始化。因为初始化只能初始一次,而构造函数体内可以多次赋值
3.2初始化列表
初始化列表:以一个冒号开始,接着是以逗号分隔的数据成员列表,每个成员变量后跟着一个放在括号中的初始值或表达式。
class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){}private:int _year;int _month;int _day;
};
注意:
- 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
- 类中包含以下成员,必须放在初始化位置进行初始化:
- 引用成员变量
- const成员变量,因为只有这一次初始化的机会。
- 自定义类型成员(且该类没有默认构造函数时)
const变量必须在定义的位置初始化,这次初始化完以后就不能改了。
class A
{
public:int _a;//声明int _a2;const int _x;//加了以后生不成默认构造//const int _x=1;给的是缺省值,不是初始化。
};
int main()
{A aa;//定义,对象整体的定义。每个成员什么时候定义呢?//必须给成员变量找一个定义的位置,不然像const这样的成员不好处理。//必须在定义的位置初始化const int i=0;return 0;
}
class B
{
private:B(int _b):_b(0){cout << "B()" << " ";}
};
class A
{
public://1.那个对象调用构造函数,初始化列表是他所有成员变量定义的位置//2.不管你是否显示在初始化列表写,那么编译器每个变量都会初始化列表定义初始化A()//构造函数{:_x(1),_a2(1),_bb(0),_ref(_a1){_a1++;//缺省值在这里用_a2--;}}
private:int _a1=1;//声明int _a2=2;const int _x;//const int _x=1;给的是缺省值,不是初始化。int& _ref;//也必须初始化,引用也必须在定义的位置初始化B _bb;//默认生成的构造函数(不传参数就可以调的那一个),对内置类型不做处理,对自定义类型进行初始化。//默认构造无参,全缺省
};
int main()
{A aa;//定义,对象整体的定义。每个成员什么时候定义呢?//必须在定义的位置初始化const int i=0;//加了以后生不成默认构造。return 0;
}
成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与在初始化列表的先后顺序无关。
- 所有的成员都会走初始化列表
- 平时写构造函数最好在初始化列表写