建网站 方法,中国纵横168网站建设系统,什么网站专做衣服,手机壁纸网站源码文章目录 1.类型转换1.1 前言1.2 类型转换的性质 2.static成员2.1 前言2.2 static的基本概念 3.友元4.内部类5.匿名对象 1.类型转换
1.1 前言 在C中#xff0c;由于程序员可以自己显示定义一个新的类。这样就会出现一个问题#xff1a;程序员自己显示定义的类类型与编译器中… 文章目录 1.类型转换1.1 前言1.2 类型转换的性质 2.static成员2.1 前言2.2 static的基本概念 3.友元4.内部类5.匿名对象 1.类型转换
1.1 前言 在C中由于程序员可以自己显示定义一个新的类。这样就会出现一个问题程序员自己显示定义的类类型与编译器中自带的隐式定义的类型发生了冲突无法进行匹配。就像整型无法赋值浮点型的数. int a 1.0;
//无法赋值浮点型因此。C支持 内置类型 / 隐式类型 转换为类类型对象。 1.2 类型转换的性质
C想要实现类型转换需要有相关内置类型为参数的构造函数。构造函数前面加 explicit 该构造函数就不再支持隐式类型转换。显示定义的类型也可以转换为隐式定义的类型也需要相应的构造函数支持。
#includeiostream
using namespace std;class A
{
public:// 构造函数explicit就不再⽀持隐式类型转换// explicit A(int a1)A(int a1)//显示定义的类型转换为int类型:_a1(a1){}//explicit A(int a1, int a2)A(int a1, int a2):_a1(a1), _a2(a2){}void Print(){cout _a1 _a2 endl;}int Get() const{return _a1 _a2;}private:int _a1 1;int _a2 2;
};class B
{
public:B(const A a):_b(a.Get()){}private:int _b 0;
};int main()
{//转换的逻辑过程// 步骤一1构造⼀个A的临时对象再⽤这个临时对象拷⻉构造aa3// 步骤二编译器遇到连续构造拷⻉构造-优化为直接构造这里类型转换完成A aa1 1;//1的隐式类型是int,A的类型是A。这里1被转换为A类型aa1.Print();const A aa2 1;A aa3 { 2,2 };//多参数的类型转换C11之后才开始支持。// aa3隐式类型转换为b对象// 原理跟上⾯类似B b aa3;//A类型的aa3转换为B类型//显式定义转换为隐式定义也是这个逻辑const B rb aa3;//引用没有拷贝过程提高程序效率return 0;
}2.static成员
2.1 前言 static 。中文意思是静态的在C中作为静态成员的关键字。用来修饰静态成员。那么在C中static 具体的作用有哪些呢接下来为各位介绍。 2.2 static的基本概念
在C中用 static 修饰的成员变量称为静态成员变量。由于静态成员变量可以被所有的类对象使用不属于某一个类对象存放在静态区中。所以静态成员变脸只能在类外初始化。用 static 修饰的成员函数称为静态成员函数。静态成员函数没有 this 指针。非静态成员函数可以访问静态成员和静态成员函数静态成员函数不能访问非静态成员因为没有 this 指针。突破类域就可以访问静态成员和静态成员函数。通过 ::静态成员 或者 对象.(静态成员) 等两种方式来访问静态成员和静态成员函数。静态成员受publicprivateprotected 等访问限制符的限制。
class A
{
public:A(){_scount;}A(const A t){_scount;}~A(){--_scount;}static int GetACount()//静态成员函数没有this指针{//_a 1;//静态成员函数不能访问非静态成员return _scount;}
private://进入private静态成员则无法被其他类访问// 类⾥⾯声明static int _scount;//静态成员变量int _a;
};class B
{
public:private://int _b1 A::_scount;//静态成员可以被所有的类访问但是同时也受到访问限制符的限制
};// 类外⾯初始化
int A::_scount 0;int main()
{cout A::GetACount() endl;//A::GetACount是访问静态成员函数的一种方式A a1, a2;A a3(a1);cout A::GetACount() endl;cout a1.GetACount() endl;//cout A::_scount endl;// 编译报错error C2248: “A::_scount”: ⽆法访问 private 成员(在“A”类中声明)return 0;
}3.友元 友元包括友元函数和友元类,本质上是一种突破类访问限定符封装的方式。让本来封装起来的函数或者类能被另一个类使用。 在函数声明或者类声明的前面加friend并且把友元声明放到⼀个类的里面。外部友元函数可访问类的私有和保护成员友元函数仅仅是⼀种声明它不是类的成员函数。友元函数可以在类定义的任何地方声明不受类访问限定符限制。⼀个函数可以是多个类的友元函数。友元类中的成员函数都可以是另⼀个类的友元函数都可以访问另⼀个类中的私有和保护成员。友元类的关系是单向的不具有交换性比如A类是B类的友元但是B类不是A类的友元。友元类关系不能传递如果A是B的友元 B是C的友元但是A不是C的友元。友元有时提供了便利。但是友元会增加耦合度破坏封装与大型项目中低耦合高聚度的要求相违所以友元不宜多用。
// 前置声明否则A的友元函数声明编译器不认识B
class B;class A
{// 友元声明friend class B;// 友元声明 函数类型和名称的前面加上friendfriend void func(const A aa, const B bb);//一个函数可以是多个类的友元//外部友元函数func可以访问类里面的私有成员_a1和_a2private:int _a1 1;int _a2 2;
};class B
{friend class C;//友元关系不共享A是B的友元B是C的友元但是A不是C的友元
public:// 友元声明friend void func(const A aa, const B bb);void func1(const A aa)//友元类的单向关系。A是B的友元但是B不是A的友元{cout aa._a1 endl;cout _b1 endl;}//friend class C;//友元声明可以在类的任何地方。一般情况下都是放在类的第一行void func2(const A aa){cout aa._a2 endl;cout _b2 endl;}
private://friend class C;//友元声明可以在类的任何地方。一般情况下都是放在类的第一行int _b1 3;int _b2 4;//friend class C;//友元声明可以在类的任何地方。一般情况下都是放在类的第一行
};class C
{
public:private:int _c1 5;
};void func(const A aa, const B bb)
{cout aa._a1 endl;cout bb._b1 endl;
}int main()
{A aa;B bb;bb.func1(aa);bb.func1(aa);return 0;
}4.内部类 如果⼀个类定义在另⼀个类的内部这个内部类就叫做内部类。内部类是⼀个独立的类跟定义在全局相比它只是受外部类类域限制和访问限定符限制所以外部类实例化的对象中不包含内部类的实例化。 内部类默认是外部类的友元类。 内部类本质也是⼀种封装当A类跟B类紧密关联A类实现出来主要就是给B类使用那么可以考虑把A类设计为B的内部类如果放到 private / protected 位置那么A类就是B类的专属内部类其他地方都用不了。
class A
{
private:static int _k;int _h 1;public:class B // B是A的内部类。B默认就是A的友元{public:void foo(const A a){cout _k endl; //可以这样调用A的私有成员cout a._h endl; //也可以这样调用A的私有成员}};
};int A::_k 1;//static定义的成员是静态变量可以在全局赋值int main()
{cout sizeof(A) endl;//由于static定义的成员不参与组成类的大小所以A的大小为4个字节一个整型A::B b;//由于内部类受到类域的限制所以使用的时候需要声明A aa;//外部类则没有限制b.foo(aa);return 0;
}5.匿名对象
用类型(实参) 定义出来的对象叫做匿名对象相比之前我们定义的类型对象名(实参) 定义出来的叫有名对象。匿名对象生命周期只在当前一行⼀般临时定义⼀个对象当前用⼀下即可就可以定义匿名对象。const定义的匿名对象则可以延长使用寿命。
class A
{
public:A(int a 0):_a(a){cout A(int a) endl;}~A(){cout ~A() endl;}
private:int _a;
};class Solution {
public:int Sum_Solution(int n) {//...return n;}
};int main()
{A aa1;aa1 1;//有名对象// A aa1(); //不能这么定义对象因为编译器⽆法识别下⾯是⼀个函数声明还是对象定义// A aa2(2);// 我们可以这么定义匿名对象匿名对象的特点不⽤取名字// 但是他的⽣命周期只有这⼀⾏我们可以看到下⼀⾏它就会⾃动调⽤析构函数A();A(1);//匿名对象const A r A();//const定义的对象声明周期与r相同r销毁匿名对象析构// 匿名对象在这样场景下就很好⽤当然还有⼀些其他使⽤场景这个我们以后遇到了再说Solution().Sum_Solution(10);return 0;
}运行结果解释