C++学习笔记03-类的默认成员函数

1 类的默认6个成员函数

如果定义了一个空类,其实不是空类,任何一个类都会有默认成员函数。
自己定义了就用定义,不定义就用默认生成的。

  • 初始化 和 清理
    构造函数:完成初始化工作
    析构函数:完成清理工作

  • 赋值 和 拷贝
    拷贝构造函数:使用同类对象初始化创建对象
    运算符重载:一个对象与另一对象进行运算

  • 取地址重载
    普通对象
    const对象

1.1 构造函数

构造函数是特殊函数,实例化时,在生成相应对象时编译器会自动调用该函数,保证每个对象都有一个合适的初始化值,并且在对象生命周期里面只能调用一次。

构造函数的基本特征:

  • 函数名 与 类名 同名
  • 无返回值
  • 对象实例化时自动调用对应构造函数
  • 构造函数可以重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数 
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name, int age) //构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21);
    
    //s1.SetStudetInfo("李三", 20);
    s1.ShowStudetInfo();
    
    return 0;
}

构造函数 重载

#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    Studet(void); //构造函数 重载
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name, int age) //构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

Studet::Studet(void) //构造函数 重载
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, "小白");
    Age = 18;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21), s2;
    
    //s1.SetStudetInfo("李三", 20);
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    
    return 0;
}

==重载构造函数 与 构造函数 合并 ==

#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name = "小白", int age = 18) //缺省构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21), s2;
    
    //s1.SetStudetInfo("李三", 20);
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    
    return 0;
}

==若不定义构造函数则是随机值,但对定义类型会初始化构造函数 ==

#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Time
{
public: //共有的
    Time(const char *name, int age) //构造函数
    {
        std::cout << "调用了Time构造函数" << std::endl;
        Year = 2022;
        Month = 10;
    }
private: //私有的
    int Year; //属性
    int Month; //属性
};

class Studet
{
public: //共有的
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
    Time Tm;
};

1.1.1 构造函数的初始化列表

  • 构造函数的初始化列表是真的初始化,在定义的时候初始化。
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
	Studet(char *name, int age); //构造函数 
    void SetStudetInfo(char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char* Name; //属性
    int Age; //属性
};

//采用初始化列表
Studet::Studet(char* name, int age): Name(name), Age(age)
{

}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21);

    s1.ShowStudetInfo();
    
    return 0;
}

注意

  • const 必需在初始化列表中初始化
  • 引用必须初始化

1.2 析构函数

析构函数与构造函数相反,是用来清理对象。对象销毁时调用一次析构函数进行清理工作。

构造函数的基本特征:

  • 析函数名 是在 类名 前加~
  • 无返回值
  • 一个类有且只有一个析构函数,如果没有显示定义,系统会自动生成默认的析构函数
  • 对象声明结束时,编译器会自动调用析构函数
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    ~Studet() //析构函数
    {
        std::cout << "调用了析构函数" << std::endl;
    }
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name = "小白", int age = 18) //缺省构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21), s2;
    
    //s1.SetStudetInfo("李三", 20);
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    
    return 0;
}

1.3 拷贝构造函数

拷贝 + 构造函数,看名字就是知道意思了。
**拷贝构造函数用于创建对象时,创建一个与一个对象一模一样的新对象。**

拷贝构造函数的基本特征:

  • 拷贝构造函数是构造函数的一个重载形式
  • 拷贝构造函数只有一个,且必须使用引用传参,如果使用传值的方式传参,将会引起无穷递归调用。
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    Studet(Studet &s); //构造函数 
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name, int age) //构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

Studet::Studet(Studet &s) //拷贝构造函数 
{
    std::cout << "调用了拷贝构造函数" << std::endl;
    strcpy(Name, s.Name);
    Age = s.Age;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21);
    Studet s2(s1);
    
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    
    return 0;
}

注意

  • 只进行字节拷贝的叫浅拷贝。自己不创建拷贝构造函数,则调用默认生成拷贝构造函数也能实现。
  • 带指针(栈)的拷贝叫深拷贝。若用默认拷贝构造函数会出问题。

1.4 运算符重载

- 函数名:==operator== 接【需要重载的运算符符号】
- 函数原型为:【返回值类型】【operator】【操作符】【参数列表】

特别注意:

  • 连接符 必须是 已有的,不能自己去创造新的操作。
  • 重载操作符对的是自己定义类型。
  • 作为类成员的重载函数时,其形参看起来比操作数目少 1 个成员,因为一个默认的this指针
  • .*, ::, sizeof, ?:, ., 这五个运算符号不能重载。
1.4.1 相等运算符重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    Studet(Studet &s); //构造函数
    bool operator == (Studet &s); //运算符重载函数
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name, int age) //构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

Studet::Studet(Studet &s) //拷贝构造函数 
{
    std::cout << "调用了拷贝构造函数" << std::endl;
    strcpy(Name, s.Name);
    Age = s.Age;
}

bool Studet::operator == (Studet &s) //运算符重载函数
{
    return Age == s.Age;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21);
    Studet s2(s1);
    
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    
    if(s1 == s1)
    {
        std::cout << "调用了运算符重载函数" << std::endl;
    }
    
    return 0;
}
1.4.2 赋值运算符重载
#include <cstring>
#include <iostream> //头文件,C++11可以不用加.h、*hxx

using namespace std; //命名空间声明

class Studet
{
public: //共有的
    Studet(const char *name, int age); //构造函数
    Studet(Studet &s); //构造函数
    Studet& operator = (Studet &s); //赋值运算符重载函数
    void SetStudetInfo(const char *name, int age); //方法
    void ShowStudetInfo(void);
    
private: //私有的
    char Name[20]; //属性
    int Age; //属性
};

Studet::Studet(const char *name, int age) //构造函数 
{
    std::cout << "调用了构造函数" << std::endl;
    strcpy(Name, name);
    Age = age;
}

Studet::Studet(Studet &s) //拷贝构造函数 
{
    std::cout << "调用了拷贝构造函数" << std::endl;
    strcpy(Name, s.Name);
    Age = s.Age;
}

Studet& Studet::operator = (Studet &s) //赋值运算符重载函数
{
	strcpy(Name, s.Name);
	Age = s.Age;
    
    return *this;
}

void Studet::SetStudetInfo(const char *name, int age) //方法
{
    strcpy(Name, name);
    Age = age;
}

void Studet::ShowStudetInfo(void)
{
    std::cout << Name << " " << Age << std::endl;
}

int main(void)
{
    Studet s1("王二", 21);
    Studet s2("李三", 20);
    
    s1.ShowStudetInfo();
    s2.ShowStudetInfo();
    s2 = s1;
    s2.ShowStudetInfo();

    return 0;
}

注意: 赋值运算符重载函数类似拷贝构造函数,同样存在浅拷贝深拷贝问题

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值