如果从C语言的视角来看,所谓类就是能够调用自身成员的结构体。而在C++中,关键字struct
虽然仍旧保留,但已非C语言中的结构体,而是表示默认成员共有的class
。
即在C++中,struct C{/*code*/}
和class C{public:/**/}
并无区别,例如下面两组代码所实现的功能是完全一致的。
//默认成员公有struct Number{private; float val;public: float pubVal; Number(float inVal);};
//默认成员为私有class Number{ float val;//外部无法直接访问public: float pubVal; Number(float inVal);};
所谓私有成员,就是外部函数不可访问的成员
void printPublic(Number num){ cout<<num.pubVal<<endl;}void printPrivate(Number num){ cout<<num.val<<endl; //报错,无法访问私有类型}
不过从C语言的视角来看,类也的确保留了一些struct
的风格,其初始化方法与指针调用便是明证。
int main(){ Number num{3.14}; //相当于引用构造函数 printNumber(num); Number* pNum = # //指向num的指针 //->表示类指针所指向的成员 cout<<pNum->pubVal<<endl; system("pause"); return 0;}
输出为
PS E:\Code\cpp> g++ .\oop.cppPS E:\Code\cpp> .\a.exe 3.143.14
由于C++对泛型具备十分良好的支持,语言本身的强大可能会导致用户在使用过程中不严谨,继而增大维护成本。例如对于如下构造函数
Number::Number(float inVal){ val = inVal;}
那么下面的几个语句都能够输出正确的值
int main(){ Number num{3.14}; printNumber(num); num = 1.414; printNumber(num); printNumber(0.618); system("pause"); return 0;}
结果为
PS E:\Code\cpp> g++ .\oop.cppPS E:\Code\cpp> .\a.exe3.141.4140.618请按任意键继续. . .
可见这三条语句都没有报错
Number num{3.14}; num = 1.414; printNumber(0.618);
第一条是没有问题的,是简单赋值语句;第二条和第三条则是暗中调用构造函数,将浮点类型的变量转换成了Number
类型,这种意义不明的代码自然会引起维护上的困难。explicit
就为解决这种问题而生的。
将构造函数用explicit
进行标记,可以有效禁止这种隐式转换
class Number{ float val;public: explicit Number(float inVal); float pubVal;};int main(){ Number num{3.14}; num = 1.414; //编译不予通过 printNumber(0.618);//编译不予通过 //...}
顾名思义,二者分别是常量与变量,前者要求成员函数不得修改类的成员变量
class Number{ float val;public: mutable float pubVal; //注意该变量用了mutable explicit Number(float inVal); void printVal() const; //该方法用了const};void Number::printVal() const{ cout<<val<<endl; /* val = val+1; //这是不被允许的 */ pubVal = val+1; //这是被允许的}
即,const
成员只能修改mutable
成员。
自引用是一种编程技巧,对于更改类状态的函数,如果将类本身作为返回值,那么就可以实现炫酷而优雅的链式操作。
class Number{ float val;public: explicit Number(float inVal); Number& addOne(); //其返回值是当前对象的地址};Number& Number::addOne(){ cout<<val++<<endl; return *this; }
其中,*this
指向调用该成员函数的对象,测试一下
int main(){ Number num{3.14}; //相当于引用构造函数 num.addOne().addOne().addOne(); system("pause"); return 0;}
结果为
PS E:\Code\cpp> g++ .\oop.cppPS E:\Code\cpp> .\a.exe 3.144.145.14请按任意键继续. . .
顾名思义,静态成员之所以被称为静态,在于其存储位置只有一个。对于一个类而言,无论创建了多少实例,类中的静态变量就只被存储在那一个位置。这意味着静态成员要比对象实例具有更长的生命周期,当一个对象被销毁之后,静态成员并没有被销毁,从而再次被调用的时候,也不必另行分配内存。
class Number{ float val; static Number defaultNum;public: explicit Number(float inVal=0); static void setDefault(float inVal); void printVal() const;};void Number::printVal() const{ cout<<val<<endl;}//定义默认NumNumber Number::defaultNum{3.14};void Number::setDefault(float val){ defaultNum = Number{val};};Number::Number(float inVal){ val = inVal ? inVal : defaultNum.val;}int main(){ Number num{}; //相当于引用构造函数 num.printVal(); system("pause"); return 0;}
输出为
PS E:\Code\cpp> .\a.exe 3.14请按任意键继续. . .
复数有实部和虚部,默认值为0,其加法和减法分别就是实部和虚部相减,其乘法为
除法为
联系客服