二手房公司如何做网站,衡阳房产网站建设,班级主页网页设计模板,公司做两个网站目录 一.类的6个默认成员函数
1.知识引入
编辑 2.构造函数
(1)概念
(2)语法特性
(3)特征
①问题引入1
②问题引入2 #xff08;缺少默认构造函数#xff09;
3.析构函数
(1)概念
(2)特性
4.拷贝构造函数
(1)概念
(2)特征
①拷贝构造函数是构造函数的一…目录 一.类的6个默认成员函数
1.知识引入
编辑 2.构造函数
(1)概念
(2)语法特性
(3)特征
①问题引入1
②问题引入2 缺少默认构造函数
3.析构函数
(1)概念
(2)特性
4.拷贝构造函数
(1)概念
(2)特征
①拷贝构造函数是构造函数的一个重载形式。
②拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错因为会引发无穷递归调用。
③若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象的内置类型成员按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。自定义类型成员调用它的拷贝构造。
5.赋值运算符重载 (1)运算符重载
① 语法及注意事项
(2)赋值运算符重载
二.总结 一.类的6个默认成员函数
1.知识引入 如果一个类中什么成员都没有简称为空类。 空类中真的什么都没有吗并不是任何类在什么都不写时编译器会自动生成6个默认成员函数。 默认成员函数用户没有显式实现编译器会生成的成员函数称为默认成员函数 示例 2.构造函数
(1)概念 构造函数是一个特殊的成员函数名字与类名相同,创建类 类型对象时由编译器自动调用以保证每个数据成员都有 一个合适的初始值并且在对象整个生命周期内只调用一次。 注意 构造函数是特殊的成员函数需要注意的是构造函数虽然名称叫构造但是构造函数的主要任务并不是开空间创建对象而是初始化对象。 (2)语法特性 函数名与类名相同。无返回值。不是void,是就不需要写对象实例化时编译器自动调用对应的构造函数。构造函数可以重载。 示例
class Date
{
public:Date()//构造函数{_year 1;_month 1;_day 1;}/*Date(int year1,int month1,int day1)带参构造函数函数重载{_year year;_month month;_day day;}*/void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};
int main()
{//调用无参构造函数Date d1;d1.Print();//调用带参构造函数/*Date d2(2024,2,8);d2.Print();*/return 0;
}
注意 注意如果通过无参构造函数创建对象时对象后面不用跟括号否则就成了函数声明以下代码的函数声明了d3函数该函数无参返回一个日期类型的对象warning C4930: “Date d3(void)”: 未调用原型函数(是否是有意用变量定义的?)//Date d3(); 通常情况只写一个构造函数避免调用时存在歧义。 (3)特征
①问题引入1 关于编译器生成的默认成员函数会有以下疑惑不实现构造函数的情况下编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用d对象调用了编译器生成的默认构造函数但是d对象_year/_month/_day依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用 class Date
{
public:void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;d1.Print();return 0;
} 解答 C把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型如int/char...自定义类型就是我们使用class/struct/union等自己定义的类型。默认生成的构造函数对于内置类型不做处理自定义类型会去调用他的默认构造函数。 class A
{
public:A(){cout A() endl;_a 0;}
private:int _a;
};
class Date
{
public:void Print(){cout _year - _month - _day endl;}
private:int _year;//也可以在这里给缺省值int _month;int _day;A _aa;
};int main()
{Date d1;d1.Print();return 0;
} 结果显示 ②问题引入2 缺少默认构造函数
class Date
{
public:Date(int year, int month, int day){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}
private://也可以在声明时给缺省值int _year1;int _month1;int _day;};int main()
{Date d1;d1.Print();return 0;
} 无参的构造函数和全缺省的构造函数都称为默认构造函数并且默认构造函数只能有一个。注意无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数都可以认为是默认构造函数。 问题存在我们写了一个带参数的构造函数编译器就不再给我们生成构造函数了。 修改
class Date
{
public:Date(){_year 1;_month 1;_day 1;}void Print(){cout _year - _month - _day endl;}
private://也可以在声明时给缺省值int _year1;int _month1;int _day;};int main()
{Date d1;d1.Print();return 0;
}
3.析构函数 (1)概念 析构函数与构造函数功能相反析构函数不是完成对对象本身的销毁局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数完成对象中资源的清理工作。 (2)特性 1. 析构函数名是在类名前加上字符 ~。 2. 无参数无返回值类型。 3. 一个类只能有一个析构函数。若未显式定义系统会自动生成默认的析构函数。注意析构函数不能重载。 4. 对象生命周期结束时C编译系统系统自动调用析构函数。 class Date
{
public:Date(){_year 1;_month 1;_day 1;}void Print(){cout _year - _month - _day endl;}~Date(){cout this endl;cout ~Date() endl;}
private://也可以在声明时给缺省值int _year1;int _month1;int _day;};
void func()
{Date d2;
}
int main()
{func();Date d1;d1.Print();return 0;
} 4.拷贝构造函数
(1)概念 拷贝构造函数只有单个形参该形参是对本类类型对象的引用(一般常用const修饰)在用已存在的类类型对象创建新对象时由编译器自动调用。 (2)特征
①拷贝构造函数是构造函数的一个重载形式。
//拷贝构造函数
class Date
{
public:Date(int year 2024, int month 1, int day 1){_year year;_month month;_day day;}//Date(const Date d) // 错误写法编译报错会引发无穷递归Date(const Date d) // 正确写法{_year d._year;_month d._month;_day d._day;}
private:int _year;int _month;int _day;
};
int main()
{Date d1(2024,1,28);Date d2(d1);return 0;
}
②拷贝构造函数的参数只有一个且必须是类类型对象的引用使用传值方式编译器直接报错因为会引发无穷递归调用。 C规定自定义类型的拷贝都会调用拷贝构造 而传引用传参则不再需要调用拷贝构造。 为什么会引发无穷递归 ③若未显式定义编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象的内置类型成员按内存存储按字节序完成拷贝这种拷贝叫做浅拷贝或者值拷贝。自定义类型成员调用它的拷贝构造。
class Date
{
public:Date(int year 2024, int month 1, int day 1){_year year;_month month;_day day;}void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024,1,28);Date d2(d1);d1.Print();d2.Print();return 0;
}
深拷贝
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack st1;Stack s2(st1);return 0;
} 程序最终崩溃这是为什么呢 问题分析 代码修改手写拷贝构造
typedef int DataType;
class Stack
{
public:Stack(size_t capacity 10){_array (DataType*)malloc(capacity * sizeof(DataType));if (nullptr _array){perror(malloc申请空间失败);return;}_size 0;_capacity capacity;}//Stack st2(st1)Stack(const Stack s){DataType* tmp (DataType*)malloc(sizeof(s._capacity * (sizeof(DataType))));if (tmp nullptr){perror(malloc fail);exit(-1);}memcpy(tmp, s._array, sizeof(DataType) * s._size);_array tmp;_size s._size;_capacity s._capacity;}void Push(const DataType data){// CheckCapacity();_array[_size] data;_size;}~Stack(){if (_array){free(_array);_array nullptr;_capacity 0;_size 0;}}
private:DataType* _array;size_t _size;size_t _capacity;
};
int main()
{Stack st1;Stack s2(st1);return 0;
}
5.赋值运算符重载 (1)运算符重载 C为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。 ① 语法及注意事项 函数原型返回值类型 operator操作符(参数列表) 注意事项 不能通过连接其他符号来创建新的操作符比如operator重载操作符必须有一个类类型参数用于内置类型的运算符其含义不能改变例如内置的整型不 能改变其含义作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this.* :: sizeof ?: .注意注意以上5个运算符不能重载。 比较两个日期相等及小于传统写法
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}//private:int _year;int _month;int _day;
};
//判断日期相等
bool DataEqual(const Date x, const Date y)
{return x._year y._year x._month y._month x._day y._day;
}
//判断日期小于
bool DateLess(const Date x, const Date y)
{if (x._year y._year){return true;}else if (x._year y._year){if (x._month y._month){return true;}else if (x._month y._month){return x._day y._day;}}return false;
}
int main()
{Date d1(2024, 1, 28);Date d2(2024, 2, 27);cout DataEqual(d1, d2) endl;cout DateLess(d1, d2) endl;return 0;
} 缺陷由于函数名可能会存在取名字不规范的情况将导致不知道这个函数的作用是什么。 因此采用运算符重载来更容易让看代码的人知道这个代码的作用增强代码可读性。 运算符重载写法
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}//private:int _year;int _month;int _day;
};
//判断日期相等
bool operator(const Date x, const Date y)
{return x._year y._year x._month y._month x._day y._day;
}
//判断日期小于
bool operator(const Date x, const Date y)
{if (x._year y._year){return true;}else if (x._year y._year){if (x._month y._month){return true;}else if (x._month y._month){return x._day y._day;}}return false;
}
int main()
{Date d1(2024, 1, 28);Date d2(2024, 2, 27);cout (d1d2) endl;//cout(operator(d1,d2)endl;cout (d1d2) endl;return 0;
}注意 这里代码能执行是因为我们将类内的成员设置成了公有权限否则在类外面是不能访问类里面的成员的。 处理方式将类外函数放入类内 class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}//判断日期相等bool operator( const Date y){return _year y._year _month y._month _day y._day;}//判断日期小于bool operator( const Date y){if (_year y._year){return true;}else if (_year y._year){if (_month y._month){return true;}else if (_month y._month){return _day y._day;}}return false;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 1, 28);Date d2(2024, 2, 27);cout d1.operator(d2) endl;cout d1.operator(d2) endl;cout (d1d2) endl;cout (d1d2) endl;return 0;
} (2)赋值运算符重载 赋值运算符重载格式 参数类型const T传递引用可以提高传参效率返回值类型T返回引用可以提高返回的效率有返回值目的是为了支持连续赋值检测是否自己给自己赋值返回*this 要复合连续赋值的含义 class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}//d1d2void operator(const Date d){_year d._year;_month d._month;_day d._day;}void Print(){cout _year - _month - _day endl;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 1, 28);Date d2(2024, 2, 27)Date d3(d1);//拷贝构造同类型一个存在的对象进行初始化要创建的对象d1 d2;//已经存在的对象,一个拷贝赋值给另一个d1.Print();d2.Print();return 0;
}
返回值问题 d1d2d3; 我们知道赋值操作是将右操作数赋值给左操作数然后将左操作数作为返回值因此该赋值函数需要有明确的返回值类型。因此要对上方代码进行部分修改 Date operator(const Date d)//这里的“”是引用{if (this ! d)//这里的“”是取地址{_year d._year;_month d._month;_day d._day;}return *this;} 赋值运算符只能重载成类的成员函数不能重载成全局函数
class Date
{
public:Date(int year 1900, int month 1, int day 1){_year year;_month month;_day day;}int _year;int _month;int _day;
};
// 赋值运算符重载成全局函数注意重载成全局函数时没有this指针了需要给两个参数
Date operator(Date left, const Date right)
{if (left ! right){left._year right._year;left._month right._month;left._day right._day;}return left;
}
// 编译失败
// error C2801: “operator ”必须是非静态成员原因赋值运算符如果不显式实现编译器会生成一个默认的。此时用户再在类外自己实现 一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值 运算符重载只能是类的成员函数。 二.总结