会飞的鱼

2020
Godam
首页 » 学习笔记 » C++ 类

C++ 类

前言

    先看了小甲鱼的C++课程,看完之后又觉得自己行了,哈哈哈,当然,肯定远远不够,却又不想扣电子书。跟着老师的安排看了学习强国上清华大学的网课,发现了很多很重要但小甲鱼没有提到的东西,比如.....

构造函数

    构造函数可以理解为给类进行初始化,在程序声明一个对象时已经为其分配好了空间,但其中的内容或者说值却是随机的,这是就需要构造函数来对其进行初始化,使对象在声明时便具有默认值,将对象空间初始化。

    构造函数分为有参和无参,无参构造函数即为默认构造函数,当我们没有特意声明一个构造函数时,编译器会默认生成一个无参构造函数。但是,当我们声明了实参构造函数之后,便不能够再使用无参构造列表了。但别忘了C++可是支持函数重载的,所以可以同时存在无参和有参的构造函数。下面我们通过实例来讲解:

class Complex{
private:
    double real, imag;
public:
    Complex(double r, double i = 0);  //第二个参数的默认值为0
};
Complex::Complex(double r,double i){
    real = r;
    imag = i;
}
     对于这个类,看以下语法能否通过:


Complex cl;  //错,Complex 类没有无参构造函数(默认构造函数)
Complex* pc = new Complex;  //错,Complex 类没有默认构造函数
Complex c2(2);  //正确,相当于 Complex c2(2, 0)
Complex c3(2, 4), c4(3, 5);  //正确
Complex* pc2 = new Complex(3, 4);  //正确
     C++ 规定,任何对象生成时都一定会调用构造函数进行初始化。第 1 行通过变量定义的方式生成了 c1 对象,第 2 行通过动态内存分配生成了一个 Complex 对象,这两条语句均没有涉及任何关于构造函数参数的信息,因此编译器会认为这两个对象应该用默认构造函数初始化。可是 Complex 类已经有了一个构造函数,编译器就不会自动生成默认构造函数,于是 Complex 类就不存在默认构造函数,所以上述两条语句就无法完成对象的初始化,导致编译时报错。


    下面我们来看一下使用函数重载的使用:

class Complex{
private:
    double real, imag;
public:
    Complex(double r);
    Complex(double r, double i);
    Complex(Complex cl, Complex c2);
};
Complex::Complex(double r)  //构造函数 1
{
    real = r;
    imag = 0;
}
Complex :: Complex(double r, double i)  //构造数 2
{
    real = r;
    imag = i;
}
Complex :: Complex(Complex cl, Complex c2)  //构造函数 3
{
    real = cl.real + c2.real;
    imag = cl.imag + c2.imag;
}
int main(){
    Complex cl(3), c2(1,2), c3(cl,c2), c4 = 7;
    return 0;
}
    根据参数个数和类型要匹配的原则,c1、c2、c3、c4 分别用构造函数 1、构造函数 2、构造函数 3 和构造函数 4 进行初始化。初始化的结果是:c1.real = 3,c1.imag = 0 (不妨表示为 c1 = {3, 0}),c2 = {1, 2},c3 = {4, 2}, c4 = {7, 0}。


    构造函数这一部分参考自C语言中文网http://c.biancheng.net/view/149.html

初始化列表

定义

    在百度百科中,关于初始化的讲解中有着初始化列表的,可以说是定义吧。。。(也不是啥定理哪来定义):一个类/结构的构造函数(英语:Constructor_(object-oriented_programming))可以在定义中于构造函数体前包含一个初始化列表,用以给类/结构的元素赋初值。例如如下程序段:

struct int_complex {
int re, im;
int_complex(): re(0), im(0){}
};
    这里的" : re(0), im(0)"就是初始化列表。
    有时“初始化列表”这个术语也用来指数组或结构初始化器中的表达式表。
    这一段就直接引用百度了。


应用

①修改const只读成员变量

    const只读型变量一旦被初始化后便不能被改变,所以大家就认为被const修饰的变量便不能被改变。通过初始化列表在构造函数时便对静态变量进行初始化,从而实现对只读型变量的修改。下面我们来看一个实例:

#include <stdio.h>
class Test
{
private:
    const int ci;  // const 作用于 C++ 中的成员变量后得到的是只读成员变量,只读成员变量是不可以出现在成员符号左边的;所以会出现第下面的错误信息;
public:
/*
    Test()  // 在这里编译器显示:ci 是一个 const 成员,没有进行初始化;因此如果要初始化 ci 成员变量,必须要在这一行进行,这个时候就让初始化列表出场了;
    {       
        ci = 10;  // 在这里编译器显示:ci 在这个类中是一个只读的成员变量;
    }
*/

    /* 由上面的语句改换如下 */
    Test() : ci(10)  // ci 在初始化之后可以改变
//因为 ci 在这里只是一个只读的成员变量,仅仅是不能出现在赋值符号
//左边而已;我们依旧可以通过指针的方式来修改 ci 里面的值;
    {
        // ci = 10;
    }
    int getCI() 
    { 
        return ci; 
    }
};
int main()
{
    Test t;

/*当这里没有手工定义上面程序中的无参构造函数的时候,
显示有“未初始化的 const 的成员”的错误;
同时的当这里没有通过类来定义对象的时候
可以通过编译,说明 const 可以修饰 C++ 中的成员变量;
*/
    printf("t.ci = %d\n", t.getCI());
    return 0;
}
     实例中的ci是 const int 类型通过构造函数test的初始化列表实现了对ci的赋值,由此可见,通过初始化列表修改了静态变量的值,其发生阶段于初始化时便将其修改,但经历初始化之后便不能再修改。


    需要提到的是,上述代码在定义ci时并未将其初始化,我在Dev中将其直接赋值后并无法编译显示C++11规则下可执行,在VS环境下就可以编译执行了

    关于修改常量的问题,下面再次引用一段代码来看一下,这段代码通过指针修改,这将使我们更加深入地理解const修饰的常量:

#include <stdio.h>

class Value
{
private:
    int mi;
public:
    Value(int i)
    {
        printf("i = %d\n", i);
        mi = i;
    }
    int getI()
    {
        return mi;
    }
};

class Test
{
private:
    const int ci;
    
    Value m2;
    Value m3;
    Value m1;
    
public:
    Test() : m1(1), m2(2), m3(3), ci(100)
    {
        printf("Test::Test()\n");
    }
    
    int getCI()
    {
        return ci;
    }
    
    int setCI(int v)
    {
        int* p = const_cast<int*>(&ci);  // 通过指针来操作常量对象;
        
        *p = v;
    }
};


int main()
{
    Test t;
    
    printf("t.ci = %d\n", t.getCI());
    
    t.setCI(10);
    
    printf("t.ci = %d\n", t.getCI());
    
    return 0;
}
     通过此实例,我们就可以看到const常量也是可以修改的,C++引入const就是为了保护不被修改,然而又创造方法去修改它,正体现出C++的灵活性。


    实例中的强制类型转换const_cast<>() 是通过引用或指针来取消所指向的const变量的const属性的,详细资料前往这里https://www.cnblogs.com/ForFreeDom/archive/2012/04/14/2447146.html

*类实在是太复杂了,今天先写到这里吧,之后通过一篇新的来补充下剩下的

C++类2http://www.godreams.cn/?post=79



文章如无特别注明均为原创! 作者: 果果, 转载或复制请以 超链接形式 并注明出处 GODAM|博客|godam
原文地址《 C++ 类》发布于2020-3-10

分享到:
打赏

评论

游客

切换注册

登录

您也可以使用第三方帐号快捷登录

切换登录

注册

sitemap