分享

C++面向对象入门这一篇就够了

 怡红公子0526 2020-01-14

文章目录

      • 1. struct和class的区别
      • 2. explicit构造
      • 3. const和mutable
      • 4. 自引用
      • 5. static
      • *复数的实现*
      • 6.成员函数重载
      • 7.运算符重载
      • 8.new
      • 9.析构函数
      • 10.friend
      • 10.类的继承
      • 11.多态
      • 12.virtual
      • 看的不过瘾?

1. struct和class的区别

如果从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;    //指向num的指针
    //->表示类指针所指向的成员
    cout<<pNum->pubVal<<endl;

    system("pause");
    return 0;
}

输出为

PS E:\Code\cpp> g++ .\oop.cpp
PS E:\Code\cpp> .\a.exe      
3.14
3.14

2. explicit构造

由于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.cpp
PS E:\Code\cpp> .\a.exe
3.14
1.414
0.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);//编译不予通过
    //...
}

3. const和mutable

顾名思义,二者分别是常量与变量,前者要求成员函数不得修改类的成员变量

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成员。

4. 自引用

自引用是一种编程技巧,对于更改类状态的函数,如果将类本身作为返回值,那么就可以实现炫酷而优雅的链式操作。

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.cpp
PS E:\Code\cpp> .\a.exe      
3.14
4.14
5.14
请按任意键继续. . . 

5. static

顾名思义,静态成员之所以被称为静态,在于其存储位置只有一个。对于一个类而言,无论创建了多少实例,类中的静态变量就只被存储在那一个位置。这意味着静态成员要比对象实例具有更长的生命周期,当一个对象被销毁之后,静态成员并没有被销毁,从而再次被调用的时候,也不必另行分配内存。

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;
}
//定义默认Num
Number 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,其加法和减法分别就是实部和虚部相减,其乘法为

(a+bi)(c+di)=(acbd)+i(ad+bc) (a+b\text{i})(c+d\text{i})=(ac-bd)+\text{i}(ad+bc)

除法为

a+bic+di=(a+bi)(cdi)c2+d2=ac+bdc2+d2+bcadc2+d2 \frac{a+b\text{i}}{c+d\text{i}}=\frac{(a+b\text{i})(c-d\text{i})}{c^2+d^2}=\frac{ac+bd}{c^2+d^2}+\frac{bc-ad}{c^2+d^2}

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多