见到好多没见过的东西,记录下来。
构造函数
原来构造函数还可以这样写:
class myDate {
private:
int year;
int month;
public:
myDate() : year(2021) {};
myDate(int y) : year(y) {};
myDate(int y, int m) : year(y), month(m) {};
};
使用new创建对象加与不加括号的区别:
-
不加括号时,对于有自建的构造函数,正常执行,如果没有自建构造函数,系统只为成员变量分配空间不初始化,例如int型会出现随机值的情况。
-
加括号时,就算没有自建构造函数,系统在为成员变量分配内存的同时赋初始值,例如int初始值是0
不加括号且没构造函数的下场:
int main() {
auto *d = new myDate;
std::cout << d->getYear(); // 39984272
}
定义指针不会触发构造函数
myDate *p;
复制构造函数
myDate::myDate(const myDate &other) {
std::cout << "复制构造函数执行啦!" << std::endl;
year = other.year;
}
int main(){
myDate p;
p.setYear(1000);
myDate p1(p);
std::cout << p1.getYear(); // 1000
return 0;
}
p对象的year属性完整的复制给了p1对象
不写复制构造函数就是全部属性复制,写了就相当于重写了,按照自己指定的复制
自动调用复制构造函数的情况有3种:
- 实例化类的时候传入要复制的类
- 函数F参数中有类A的对象时,会复制类A
- 函数F返回值是类A的对象,会复制类A
类型转换构造函数
int main() {
myDate p(2000);
std::cout<<p.getYear()<<std::endl;
p = 2021;
std::cout<<p.getYear()<<std::endl;
}
/*
output:
构造函数:y = 2000
2000
构造函数:y = 2021
2021
*/
p = 2021,表面上看这是一条赋值语句,十几箱,他将2021创建为临时myDate对象,然后使用这个对象为p赋值。
析构函数
~myDate(){
std::cout<<"析构函数执行啦!"<<std::endl;
}
析构函数没有参数也没用返回值,会在对象消亡时执行。
释放对象指针数组内存空间
int main(){
myDate *ss[2] = {new myDate(2020),new myDate(2021)};
delete ss[0];
delete ss[1];
return 0;
}
/* output:
构造函数:y = 2020
构造函数:y = 2021
析构函数执行啦!
析构函数执行啦!
*/
类的静态成员
静态变量
全局变量是指在所有花括号之外声明的变量,其作用域范围是全局可见的,即在整个项目文件内都有效。使用static修饰的全局变量是静态全局变量,其作用域有所限制,仅在定义该变量的源文件内有效,项目中的其他源文件中不能使用它。
使用static修饰的局部变量是静态局部变量,即定义在块中的静态变量。静态局部变量具有局部作用域,但却有全局生存期,也就是说,静态局部变量在程序的整个运行期间都存在,它占据的空间一直到程序结束才释放,但仅在定义它的块中有效,在块外不能访问它。
静态变量均存储在全局数据区,静态局部变量只执行一次初始化。
函数中声明的静态变量仅在函数体中可见。
类的静态成员
静态成员变量是类的所有对象共享的。
静态函数里不能访问类中的非静态成员,只能处理类中的静态成员变量。
静态函数与静态函数之间、非静态函数与非静态函数之间是可以相互调用的。
非静态成员函数可以调用静态成员函数,静态成员函数不能调用非静态成员函数。
类中的静态成员变量只能在类外赋值,写法如下:
class Obj{
static int num;
};
int Obj::num = 1;
访问类中的变量的3种方式:
cout<<Obj::num;
const auto p = new Obj;
cout<<p->num<<endl;
Obj p;
cout<<p.num<<endl;
类中的常量成员和常引用成员
常量对象不能调用非常量成员函数:
#include <iostream>
using namespace std;
class Obj{
public:
Obj(){}
void set() {
cout<<"普通成员函数"<<endl;
}
void get() const {
cout<<"常量成员函数"<<endl;
}
};
int main(){
Obj o;
o.get();
o.set();
const Obj co;
co.get();
co.set(); // error!
return 1;
}
此时为set添加一个常量成员函数:
void Obj::set() const{
cout<<"常量成员函数"<<endl;
}
此时就不报错了,可以看做重载函数,编译器会自动找到常量成员函数调用。
类中的常引用型变量必须在构造函数初始化,不能在程序中修改对象中的引用,否则会报错。