C++中的构造函数

C++中默认构造函数和复制构造函数需要特殊理解。

目前来看,复制构造函数可能也会因为编译器的不同体现出不同的调用机制。

以下程序创建了一个只含有基本数据类型的类,可以一定程度上帮助你理解c++中的构造函数。

/*

   by程慕峣 2022/05/10

 */


#include<iostream>   // 需要使用std::cout、std::endl
using namespace std; // 将std::cout、std::endl分别缩写为cout和endl

//vec是向量vector的缩写,表示一个二位向量
//因为c++中有一个名为vector的模板,所以,不用那个名字
class vec{
    private:
        double x, y;
    public:

        // 默认构造函数,如果默认构造函数什么都不做的话等于没写(意思就是没写也行)
        /* 要注意按照C++语言的风格,默认构造函数只应该对必须初始化的成员初始化,例如指针和引用。
         * 默认构造函数构造的是一个“没有值”的对象,而不是“等于0”的对象,如果需要区分“没有值”的情况,就该在默认构造中在留下标记,
         * 例如本案例可以加一个布尔变量c,默认构造函数将其赋值为false,有参数的构造函数赋值为true,
         * 复制构造函数不改变值,再写一个状态函数输出c的值,就可以知道一个对象有没有被正确地初始化。
         * 需要注意的是,按照前文逻辑,如果类中包含其他类的成员或继承于其他类,也不应在默认构造函数中显示调用其他类的构造函数(不写出来,让它自己跑),
         * 让其他类自动调用自己的默认构造函数往往是恰当的  */
        vec() { cout << "Default constructor has constructed. "<< endl; }

        /* 一个没什么特点的构造函数要,注意 成员(值) 的格式,这里y是成员,yy是传入值。
         * 在声明变量时直接使用变量名后加括号可以理解为利用括号中的参数为变量初始化,例如 int a(1)等价于int a=1 */
        vec(double xx, double yy) : x(xx), y(yy) {
            cout << "A constructor has constructed (" << this->x << "," << this->y << "). " << endl;
        }

        // 复制构造函数(特征只有一个参数,是同类对象的引用或常引用,即vec &b或者是const vec &b)
        /* 理论上来说,复制构造函数会在以下几种情况被调用
         *  (请做实验验证,简单的对象有、复制时有可能会跳过复制构造函数,但对于考试如下理论都成立)
         * 1. 在赋值号(“=”)右边是一个对象变量时,例如a=b ,vec a=b是初始化对象,不属于此类。
         *    如果你学习面对对象编程,你应该要明白变量(或者说对象)和值(或者说匿名变量)的区别,例如a=vec(1,2)
         *    a是向量变量,而vec(1,2)可以认为是一个向量值。
         * 2. 用一个对象初始化另一个对象时,例如vec a=b或vec a(b)
         *    以上还有一个特殊情况,例如下文中用函数重载了正号运算符,返回了*this,也就是返回自己,
         *    但是我们知道,C++中返回自己不会真的返回“自己”,而是创建新的匿名变量,用来存储复制的“自己”,
         *    这个复制过程属于用一个对象初始化另一个对象,所以也会调用复制构造函数。
         *    注意:在本案例中+vec(1,2)会导致复制构造函数被调用,而vec(vec(1,2))不会,        *    这可能是编译器的机制防止我们搁这搁这。
        vec(const vec &b) : x(b.x), y(b.y) {
            cout << "Copy constructor has constructed (" << this->x << "," << this->y << "). " << endl;
        }

        //x,y属性是private,外界不能直接调用,也就是说声明vec a没法直接用a.x和a.y
        //于是你需要用a.X()和a.Y()来获取a的属性。
        //这里的两个方法是取x,y的值,那咋对这哥俩赋值呢?你可以写两个赋值函数,但我个人认为,
        //对于向量来说,只有两个元素,还单独的用函数来设置一个元素有点蛋疼了,
        //例如向量a值为(3,4)我想把它改成(3,5),写a=vec(3,5)或a=vec(a.X(),5),
        //也就是说构造函数其实也是对变量赋值的好方法,而且能让调用过程看起来更加优雅。
        //但是假如说我这个对象有100个int32成员(0.4k),我只要改一个成员的值,
        //那专门写一个赋值函数改这个元素效率是更高的,在对变量重新赋值就很拖时间了。
        double X() { return this->x; }
        double Y() { return this->y; }

        //以下是对运算符的重载,写这些是为了让二维向量更像二维向量
        vec operator+(vec AnotherVector) { return vec(this->x + AnotherVector.x, this->y + AnotherVector.y); }//加法
        vec operator-(vec AnotherVector) { return vec(this->x - AnotherVector.x, this->y - AnotherVector.y); }//减法
        vec operator+() { return *this; }//正号
        vec operator-() { return vec(-(this->x), -(this->y)); }//负号
        vec operator*(double times) { return vec(times * (this->x), times * (this->y)); }//右乘 即a*b等价于a.operator(b),这是a*b和b*a就不一定等价了(定义的乘法不一定遵守交换律)
};


int main(int argn,char** agrv){
    //你可以直接用构造函数表示该类型变量的一个值:vec(1,2)表示二维向量(1,2),这就好像你可以用数字“1”表示一个int变量。
    // 如果说这样还有点抽象,你可以认为int a=1 和 vec b=vec(1,2)的意义是差不多的。
    // Java中vec的赋值时vec a = new vec(1,2),C++也有new,那为什么不用(甚至不能)写呢?
    // 因为new指3个操作,先开辟一个内存区域,然后把后面的东西算出来,放到这个区域去,
    // 随后返回这个区域的地址。Java中的对象都是指针,声明时不分配内存。
    // C++不一样,变量是变量,指针是指针,变量声明时就已经有了“应许之地”了,不用new分配内存
    // 如果a是个指针,就要new。例如vec* a; a= new vec(1,2); delete a;最后要显示执行delete,
delete a会把a指向区域释放,避免内存泄漏。
    vec a = vec(1, 2);
    cout << "line 65: a is (" << a.X() << "," << a.Y() << "). " << endl;


    vec b;        //等价于vec b();
    b = vec(3, 4);//给向量b赋值,可以注意到a和b做了一样的事情,构造函数调用却有区别,自然的,你在这里不可以用b(3,4)
    cout << "line 71: b is (" << b.X() << "," << b.Y() << "). " << endl;


    // 如果你能搞明白运算符重载,那就可以明白为什么这里调用了一次复制构造函数,否则不需要理解
    a = (-(+a) + (-vec(1, 2) + (+vec(2, 0)))) - b * 2; //这一行的代码是告诉读者:经过运算符重载后这样写是可以的,你可以用高中知识进行计算,看看是否相等
    cout << "line 76: a is (" << a.X() << "," << a.Y() << "). " << endl;


    a = b;
    cout << "line 80: a is (" << a.X() << "," << a.Y() << "). " << endl;
    cout << "line 81: b is (" << b.X() << "," << b.Y() << "). " << endl;

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值