目录
构造函数的初始化列表
在之前说过构造函数时,都是在函数体中进行初始化,构造函数也可以在初始化列表中进行对初始化操作,这样就使构造函数看着更加简洁美观。
初始化列表的使用方式是在函数括号的后面加上冒号,用逗号隔开以形成列表,对成员对象进行赋值初始化
在值括号中可放值或者表示式,而每个成员变量在初始化列表中只能出现一次。
在初始化列表中没有出现的成员变量,C++11支持缺省值给那些没出现在初始化列表的变量初始化,如果说某个变量又有缺省值又有初始化列表,那么它的值最终就是初始化列表的值。
引用成员变量、const成员变量、没有默认构造的类类型变量,必须放在初始化列表位置进行赋值,否则会引发编译报错。
成员变量最终都会在初始化列表中进行初始化 ,如果设置缺省值,才会使用缺省值,但是如果没有缺省值,没有出现在初始化列表,那么就会交由编译器处理,一般都是随机值。
初始化列表并不是按照列表的顺序进行初始化,而是按照变量声明的顺序进行初始化。
cpp
#include<iostream>
using namespace std;
class A
{
public:
A(int _a)
:a(_a)
,c(a)
{}
int c;
int a;
};
int main()
{
A ac(10);
cout<<ac.a<<endl;
cout << ac.c;
return 0;
}
看以上的代码,我先将c先定义,然后再初始化列表中对变量进行赋值,如果看初始化列表的顺序,那么打印结果肯定是两个变量都是10,但是是按照声明顺序,那么结果就是
c是随机值。
隐式类型转换
C++支持内置类型转换为类类型对象,需要有相关内置类型为参数的构造函数。
构造函数前面加explicit关键字就不会再支持隐式类型转换
比如这样的代码就会报错:
cpp
#include<iostream>
using namespace std;
class A
{
public:
//没有定义相关类型参数的构造函数
int c;
int a;
};
int main()
{
A ac=1;//隐式类型转换
return 0;
}
这样的代码也会报错:
cpp
#include<iostream>
using namespace std;
class A
{
public:
explicit A(int _a)//explicit关键字修饰
:a(_a)
,c(a)
{}
int c;
int a;
};
int main()
{
A ac=1;
return 0;
}
static成员
在C++中,静态成员变量需要在类的外部进行初始化,但这一规则有一个例外情况:当静态成员变量被声明为constxepr时,可以在类内部直接初始化。
static成员变量为所有类对象共享,不属于某个具体的对象,因为它并不存在于对象中,存在于静态区中。
static修饰的成员函数(静态成员函数)没有this指针,静态成员函数总可以访问其他的静态成员,但是不能访问非静态的成员,因为没有this指针。
非静态函数可以访问静态变量和静态函数。
突破类域就可以访问静态成员,可以通过类名::静态成员 或者对象.静态成员 访问静态成员变量或者函数。
静态成员也是类的成员,受到public 、private 、protected限制。
静态成员不能在声明位置给缺省值初始化,因为缺省值也是构造函数初始化列表的,静态成员不属于某个对象。
在这里可以用一个代码来统计某个类生成的对象个数。
cpp
#include<iostream>
using namespace std;
class A
{
public:
A()
{
count++;
}
A(A& a)
{
count++;
}
~A()
{
count--;
}
static int count;
};
int A::count = 0;//类外初始化
int main()
{
A a;
A b;
A c(a);
cout << A::count;//如果是用private修饰的count就不能这么写,需要用额外的函数调用
return 0;
}
cpp
class Sum
{
public:
Sum()
{
_ret += _i;
++_i;
}
static int GetRet()
{
return _ret;
}
private:
static int _i;
static int _ret;
};
int Sum::_i = 1;
int Sum::_ret = 0;
class Solution {
public:
int Sum_Solution(int n) {
Sum arr[n];
return Sum::GetRet();
}
};
友元
在类中用private、protected访问限定符修饰的成员是无法访问的,如果用友元(也就是在函数或者类声明前加上friend,并且友元放在类中)突破限制直接访问私有和保护成员。
友元只是一种声明,一个函数可以是多个类的友元。
友元类中的成员函数可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。
友元是单向的不相互,A是B的友元但B不是A的友元;并且友元不能传递,A是B的友元,B是C的友元,但A不是C的友元。
注意:友元虽然提供了便利,但是增加了耦合度,破坏封装性,不建议多用。
cpp
//由ai生成
#include <iostream>
using namespace std;
class MyClass {
private:
int secret;
public:
MyClass(int s) : secret(s) {}
// 声明友元函数
friend void revealSecret(MyClass &obj);
};
// 定义友元函数
void revealSecret(MyClass &obj) {
cout << "The secret is: " << obj.secret << endl;
}
int main() {
MyClass myObj(42);
revealSecret(myObj); // 调用友元函数
return 0;
}
cpp
#include<iostream>
using namespace std;
class A
{
private:
friend void print()
{
cout << "a" << "b"<< endl;
}
int a, b;
};
class B
{
friend class A;//友元类
private:
int a1;
int a2;
};
内部类
定义在类中的类叫做内部类,但是内部类是独立的一个类,跟全局的类相比,内部类也像个成员一样受到访问限定符的限制。
内部类默认是外部类的友元,比如说class A中定义class B,那么class B默认是class A的友元。
内部类本质也是一种封装,class B(内部类)定义出来主要是给class A(外部类)使用,如果说class A受到private和protected限制,class B只能给class A使用。
这道题也可以使用内部类解决:
cpp
class Solution {
// 内部类
class Sum
{
public:
Sum()
{
_ret += _i;
++_i;
}
};
static int _i;
static int _ret;
public:
int Sum_Solution(int n) {
Sum arr[n];
return _ret;
}
};
int Solution::_i = 1;
int Solution::_ret = 0;
匿名对象
用 类型()定于出来的对象叫匿名对象,相比之前我们定义的对象是有名对象。匿名对象生命周期很短,只有一行,匿名对象只可暂时使用。
cpp
#include<iostream>
using namespace std;
class A
{
public:
void print()
{
cout << "a" << "b"<< endl;
}
int a, b;
};
int main()
{
A().print();//使用匿名对象来调用A类中的函数
return 0;
}
以上是我对C++类和对象的学习,如有错误,欢迎指正。