C++ ——构造函数

1、作用:创建对象时,给对象的属性进行初始化

2、特点

(1)构造函数与类同名

(2)如果没有显式给出构造函数,编译器会给出默认的构造函数(参数为空,并且函数体也为空);如果给出任意的构造函数,系统默认的构造函数就不存在了

(3)有返回值,但是不写返回值类型,也不可以写void

(4)构造函数是在创建对象时自动调用

3、构造函数支持函数重载

4、构造函数也支持函数默认值

1、无参构造函数

编译器默认的构造函数:

复制代码
    类名(){
复制代码
   }
复制代码
#include <iostream>
复制代码
using namespace std;
复制代码
class Phone{
复制代码
private:  
复制代码
    string brand;  //品牌
复制代码
    string color;  //颜色
复制代码
    double price;  //价格
复制代码
public:
复制代码
    void play_music() {
复制代码
        cout<<"播放音乐"<<endl;
复制代码
    }
复制代码
    void play_video(){
复制代码
        cout<<"播放视频"<<endl;
复制代码
    }
复制代码
    //无参构造函数
复制代码
    Phone(){
复制代码
        cout<<"构造函数"<<endl;
复制代码
    }
复制代码
};
复制代码
int main(){
复制代码
    //无参构造函数
复制代码
    Phone p1;
复制代码
    return 0;
复制代码
}

2、有参构造函数

复制代码
#include <iostream>
复制代码
using namespace std;
复制代码
class Phone{
复制代码
private: 
复制代码
    string brand;  //品牌
复制代码
    string color;  //颜色
复制代码
    double price;  //价格
复制代码
public:
复制代码
    void play_music() {
复制代码
        cout<<"播放音乐"<<endl;
复制代码
    }
复制代码
    void play_video(){
复制代码
        cout<<"播放视频"<<endl;
复制代码
    }
复制代码
    //有参构造函数
复制代码
    Phone(string a,string b,double c=2995){
复制代码
        brand=a;
复制代码
        color=b;
复制代码
        price=c;
复制代码
    }
复制代码
};
复制代码
int main(){
复制代码
    //有参构造函数(栈内存对象)
复制代码
    Phone p2("vivo","红",9);
复制代码
    //有参构造函数(堆内存对象)
复制代码
    Phone*p3=new Phone("oppo","蓝",4);
复制代码
    delete p3;
复制代码
    p3=NULL;
复制代码
    return 0;
复制代码
}

3、构造初始化列表

构造初始化列表:就是构造函数的一种简便写法

注意:构造初始化列表与构造函数不能同时出现

复制代码
#include <iostream>
复制代码
using namespace std;
复制代码
class Person{
复制代码
private: 
复制代码
    int id;
复制代码
    string name;
复制代码
    string sex;
复制代码
    bool flag;
复制代码
public:
复制代码
    //构造初始化列表
复制代码
    Person(int id,string name,string sex,bool flag)
复制代码
        :id(id),name(name),sex(sex),flag(flag){}
复制代码
    void show(){
复制代码
        cout<<id<<name<<sex<<endl;
复制代码
    }
复制代码
};
复制代码
复制代码
int main(){
复制代码
    Person p1(1001,"张三","男",true);
复制代码
    p1.show();
复制代码
    return 0;
复制代码
}

4、拷贝构造函数

作用:用于实现对象的拷贝创建

特点:

(1)拷贝构造函数与构造函数构成重载(拷贝构造函数也是与类同名)

(2)如果不给出拷贝构造函数,编译器会给出默认的拷贝构造函数,完成对象之间的值复制;如果给出拷贝构造函数,编译器就不会提供默认的拷贝构造函数

(3)拷贝构造函数的参数类型是对象的引用或者是const修饰的对象的引用

(4)拷贝构造函数是在拷贝创建对象时自动调用

注意:对象之间是相互独立的,对象之间的属性也是相互独立的

4.1 浅拷贝

编译器默认给出的拷贝构造函数,完成的就是浅拷贝,会完成对象之间简单的值复制

复制代码
#include <iostream>
复制代码
using namespace std;
复制代码
class Person{
复制代码
private:  
复制代码
    int id;
复制代码
    string name;
复制代码
    string sex;
复制代码
    bool flag;
复制代码
public:
复制代码
    //构造初始化列表
复制代码
    Person(int id,string name,string sex,bool flag)
复制代码
        :id(id),name(name),sex(sex),flag(flag){}
复制代码
    //编译器给出的默认的拷贝构造函数(手写出来的)----->浅拷贝 
复制代码
    Person(const Person&p){
复制代码
        id=p.id;
复制代码
        name=p.name;
复制代码
        sex=p.sex;
复制代码
        flag=p.flag;
复制代码
    }
复制代码
    void show(){
复制代码
        cout<<id<<name<<sex<<endl;
复制代码
    }
复制代码
};
复制代码
int main(){
复制代码
    Person p1(1001,"张三","男",true);  //调用有参的构造函数
复制代码
    p1.show();
复制代码
//    //方法一:
复制代码
//    Person&pp=p1;
复制代码
//    Person p2(pp);
复制代码
    //方法二:
复制代码
    Person p2(p1);  //调用拷贝构造函数
复制代码
    p2.show();
复制代码
    return 0;
复制代码
}

默认拷贝构造函数存在安全隐患:如果成员变量是指针类型,两个对象的指针类型属性指向同一个内存空间,破坏了对象的独立性,那么这种拷贝叫浅拷贝

解决方法:使用深拷贝

4.2 深拷贝

实现方式:创建对象时,指针属性要有自己独立的区域;拷贝对象时,由地址拷贝变成内容拷贝

复制代码
#include <iostream>
复制代码
#include <string.h>
复制代码
using namespace std;
复制代码
class Animal{
复制代码
private:
复制代码
    string kind;  //种类
复制代码
    double weight;  //体重
复制代码
    char*hobby;  //爱好
复制代码
public:
复制代码
    //构造函数---->深拷贝
复制代码
    Animal(string k,double w,char*h){
复制代码
        kind=k;
复制代码
        weight=w;
复制代码
        //创建对象时,指针属性要有自己独立的区域
复制代码
        hobby=new char[20];
复制代码
        strcpy(hobby,h);  //使用strcpy前,需要引入string.h头文件
复制代码
    }
复制代码
    //展示信息
复制代码
    void show(){
复制代码
        cout<<"种类:"<<kind<<",体重:"<<weight<<",爱好:"<<hobby<<endl;
复制代码
    }
复制代码
    //kind读接口
复制代码
    string get_kind(){
复制代码
        return kind;
复制代码
    }
复制代码
    //拷贝构造函数---->深拷贝
复制代码
    Animal(const Animal&c){
复制代码
        kind=c.kind;
复制代码
        weight=c.weight;
复制代码
        //拷贝对象时,由地址拷贝变成内容拷贝
复制代码
        hobby=new char[20];
复制代码
        strcpy(hobby,c.hobby);
复制代码
    }
复制代码
};
复制代码
int main(){
复制代码
    char h[20]="eat fish";
复制代码
    Animal cat1("小猫",12,h);  //调用有参构造函数
复制代码
    cat1.show();
复制代码
    Animal cat2(cat1);  //调用拷贝构造函数
复制代码
    cat2.show();
复制代码
    return 0;
复制代码
}

4.3 隐式调用构造函数

截止到目前,对于构造函数的调用都是显式调用

隐式调用构造函数的出现情况:

(1)等号赋值时,等号左侧是对象类型,等号右边恰好是对象构造函数所需要的参数类型,这时就会把右侧值传入到构造函数中,相当于隐式调用构造函数

复制代码
#include <iostream>
复制代码
using namespace std;
复制代码
class Test{
复制代码
private:
复制代码
    int number;
复制代码
public:
复制代码
    Test(int number)
复制代码
        :number(number){}
复制代码
    int get_number(){
复制代码
        return number;
复制代码
    }
复制代码
};
复制代码
int main(){
复制代码
//    Test t1(100);  //显示调用构造函数
复制代码
//    cout<<t1.get_number()<<endl;
复制代码
//    Test*t2=new Test(8);  //显示调用构造函数
复制代码
//    cout<<t2->get_number()<<endl;
复制代码
//    delete t2;
复制代码
//    t2=NULL;
复制代码
//    Test t3(t1);  //显示调用构造函数
复制代码
//    cout<<t3.get_number()<<endl;
复制代码
    Test t4=9;  //隐式调用构造函数
复制代码
    cout<<t4.get_number()<<endl;
复制代码
    Test t5=t4;  //隐式调用构造函数
复制代码
    cout<<t5.get_number()<<endl;
复制代码
    return 0;
复制代码
}

(2)隐式调用构造函数,一般在程序员不自知的情况下产生的,需要规避掉,可以用explicit关键字屏蔽

复制代码
class Test{
复制代码
private:
复制代码
    int number;
复制代码
public:
复制代码
    explicit Test(int number)
复制代码
        :number(number){}
复制代码
    int get_number(){
复制代码
        return number;
复制代码
    }
复制代码
};
相关推荐
白总Server几秒前
Bash和Zsh在处理大文件时优化方法
开发语言·网络·ide·stm32·安全·udp·bash
苦逼的老王19 分钟前
java之uniapp实现门店地图
java·开发语言·uni-app
一条晒干的咸魚25 分钟前
【C#学习笔记03】进制转换与反码、补码、原码
开发语言·笔记·学习·c#
恋恋风辰43 分钟前
QT系列教程(13) 事件系统
c++·qt·事件系统
十年之少1 小时前
内存检测工具——Qt Creator
开发语言·qt
网络安全(king)1 小时前
基于java社交网络安全的知识图谱的构建与实现
开发语言·网络·深度学习·安全·web安全·php
Chenyu_3101 小时前
05.基于 TCP 的远程计算器:从协议设计到高并发实现
linux·网络·c++·vscode·网络协议·tcp/ip·算法
论迹2 小时前
【二分算法】-- 三种二分模板总结
java·开发语言·算法·leetcode
机器视觉知识推荐、就业指导2 小时前
C++ 与 Qt 的内存管理机制
c++·qt
五花肉村长2 小时前
Linux-基础开发工具
linux·运维·服务器·开发语言·c++·visualstudio