新型网站建设,wordpress主页编辑,html基础试题及答案,哈尔滨seo和网络推广文章目录1、const成员2、取地址及const取地址操作符重载3、构造函数续集1、初始化列表2、explicit关键字4、static成员5、匿名对象6、友元1.友元函数2、友元类7、内部类1、const成员
看一段代码
class A
{
public:void Print(){cout _a endl;}
private:int…
文章目录1、const成员2、取地址及const取地址操作符重载3、构造函数续集1、初始化列表2、explicit关键字4、static成员5、匿名对象6、友元1.友元函数2、友元类7、内部类1、const成员
看一段代码
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* aa, 而Print函数能接受的参数类型应当是A* this所以权限放大了我们只要在类里面加上const。this指针的类型无法改变因为他是一个隐含参数所以要在函数上加上const。 void Print() const{cout _a endl;}对于内部不改变成员变量的成员函数最好const修饰。在上篇的日期类中比较函数Print等也可以加上const。
2、取地址及const取地址操作符重载
这个重载也是默认成员函数它也会自动生成如果需要访问到指定的内容就需要手动写。 const A aa;aa.Print();cout aa endl;手动写默认函数可以这样 A* operator(){return this;}const A* operator() const{return this;}但没必要自动生成的就够了。但有一些特殊需求就得自己写。
3、构造函数续集
1、初始化列表
如果这样写类
class A
{
public:int _a1;int _a2;const int _a3;
};int main()
{A aa;return 0;
}程序就会报错显示有未初始化的成员就是_a3.为什么默认构造函数没有初始化它系统虽然处理内置类型但不处理const修饰的类型所以const修饰的变量需要我们在定义处初始化A aa是对类这个整体的定义里面的成员会依据构造函数处理而const修饰的成员变量要在外围单独初始化。当然类里面给const修饰的变量缺省值也可。
不过这样写不够好C把它也放到类里也就是初始化列表对特殊变量的初始化放在一起。即使main函数体里也有对特殊变量的初始化也还是按照类里的去定义因为初始化只有一次再之后不会再初始化。 A():_a3(2){_a1;}把对_a1的使用放在声明之前也没问题都在类里编译器还是会按照_a1的初始化值去。初始化列表用冒号开头中间连接用逗号
class A
{
public:A():_a3(2), _a2(1){_a1;}void Print(){cout _a1 endl;cout _a3 endl;cout _a2 endl;}
private:int _a1 1;int _a2 2;const int _a3;
};打印的结果是2 2 1.这里的规则是 初始化列表是它所有成员变量定义的位置 不管是否显示在初始化列表编译器的每个变量都会被初始化列表去初始化 初始化列表有对某个变量的初始化那就按照它给的值去执行如果没有那就按照构造函数去执行。
C规定const修饰的变量引用类型的变量用到其他类里的成员变量必须在初始化列表里初始化。用到其他类的成员变量也可以说是没有构造函数的自定义类型成员它会是这样存在的
class B
{
public:B():_b(0){cout B endl;cout _b endl;}
private:int _b;
};把它放到A前面然后在A里
private:int _a1 1;int _a2 2;const int _a3;B _b;那在调用aa.Print()时就会打印出B。我们也可以在B类初始化时写全缺省那么_b的值就会按照全缺省去实现但如果不是全缺省就无法调用构造函数。 B(int _b):_b(0){cout B endl;}那么就要在A里的初始化列表去初始化 A():_a3(2), _a2(1), _b(0){_a1;_a2--;}因为在初始化列表的变量列表都可以去找初始化的办法所以写代码的时候可以把所有初始化都放在初始化列表里。
在类里初始化的顺序是按照声明的顺序去做的所以这方面也要注意。
2、explicit关键字
现在看这一段代码
class A
{
public:A(int a):_a1(a){cout A(int) endl;}A(const A aa):_a1(aa._a1){cout A(const) endl;}void Print() {cout _a1 _a2 endl;}
private:int _a1;
};int main()
{A aa1(1);A aa2 1;return 0;
}对于aa2来说这是一个隐式类型转换1去创建一个A类型的临时变量然后这个变量再去拷贝构造aa2这个变量。类里已经有了拷贝构造函数但是打印结果的时候却没有A(const)没有调用拷贝构造是因为编译器把它变成了用1来做构造相当于aa2(1)减少工作量。
加一行代码 const A ret 10。只有加上const才没有错误。这时候就是一个类型转换引用针对的就是生成的临时变量。
如果不想类型转换那么就在函数前加上explicit代码就不可以转换了。这个对于单参数构造函数是有用的。多参数构造函数就需要这样用。 A(int a1, int a2):_a1(a1),_a2(a2){}private:int _a1;int _a2;A aa2(1, 1);A aa3 { 1, 1 };const A ret { 1, 1 };这样也会调用拷贝构造。
4、static成员
创建一个类计算创建了多少个类对象。
我们可以用构造函数来计算。假设用一个全局变量来存储数值这是不行的会和库里的变量冲突我们可以不展开命名空间using namespace std用什么展开什么 using std::cout using std::endl。但是全局变量是难以控制的。C为了解决这个问题把这个变量放到了类里面并且加上了static。
class A
{
public:A(int a 0){count;}A(const A aa){count;}static int count;//属于所有对象属于整个类
};
但是不能在类里面初始化这个值这个变量是共有的应当在类外面初始化 int A::count 0。在外部想要打印时可以这样
cout A::count endl;
cout aa2.count endl;
A* ptr nullptr;
cout ptr-count endl;不过如果count为私有变量上面几个方式就不行。那么我就可以在类里面写个函数外边调用这个函数即可。
假设没有创建对象比如把创建的代码放在一个函数里而不是在main函数里。
void func()
{A aa1;A aa2(aa1);A aa3 1;
}还是用static让类里计算数值的函数变成静态函数这样的优势就是没有this指针它是静态区的在外面就可以用A::函数名来调用。
int main()
{ func();cout A::GetCount() endl;
}静态函数里不能使用类里的非静态变量因为没有this无法调用这些变量。
静态函数服务于静态变量其它的不得插手。
void func()
{A aa1;A aa2(aa1);A aa3 1;A aa4[10];
}这个的调用次数就是13因为aa4给数组里的10个元素都初始化了也就是调用了10次。
5、匿名对象
创建类对象时不能A aa()这样因为编译器不知道这是函数还是类但可以这样写A()这是匿名对象。匿名对象的生命周期只在这一行它没有名字可以调用成员函数可以把它当做正常的类对象使用但仅仅在这一行到了下一行它就没有了。
6、友元
1.友元函数
友元之前写过分为友元类和友元函数虽然可以突破封装可以作为一个类外部的函数访问类的私有成员在类里用friend关键字声明即可。但它破坏了封装所以尽量少用 友元函数特征 友元函数可访问类的私有和保护成员但不是类的成员函数 友元函数不能用const修饰 友元函数可以在类定义的任何地方声明不受类访问限定符限制 一个函数可以是多个类的友元函数 友元函数的调用与普通函数的调用原理相同 2、友元类
甲类是乙类的友元类那么甲类就可以直接访问乙类的私有成员。但是乙类不能访问甲类。
7、内部类
内部类就是在类的里面再定义一个类。
class A
{
private:int a;
public:class B{private:int b;};
};int main()
{A aa;cout sizeof(aa) endl;return 0;
}结果是4.调试起来后查看aa的内容也只有一个a。这个内部类B和定义在全局的B并无二意空间上是独立的但它受A的类域限制在外部只能指定访问A::B但如果内部类是私有的也不能访问。
内部类B是A的友元也就是B里面可以直接访问A的私有成员。
结束。