东莞网站的优化,优秀网站设计,ftp中如何找到网站首页,天元建设集团有限公司第八建筑工程公司类的新功能
默认成员函数
在C11之前#xff0c;一个类中有如下六个默认成员函数#xff1a;
构造函数。拷贝构造函数赋值重载析构函数取地址重载函数const取地址函数
其中前四个默认成员函数最重要#xff0c;后面两个默认成员函数一般不会用到#xff0c;这里默认成员…类的新功能
默认成员函数
在C11之前一个类中有如下六个默认成员函数
构造函数。拷贝构造函数赋值重载析构函数取地址重载函数const取地址函数
其中前四个默认成员函数最重要后面两个默认成员函数一般不会用到这里默认成员函数是我们不写编译器会自动生成的函数。在C11标准中又增加了两个默认成员函数分别是移动构造函数和移动赋值重载函数。 移动构造函数的生成条件自己没有实现移动构造函数并且自己没有实现析构函数、拷贝构造函数和赋值重载函数。移动赋值重载函数的生成条件自己没有实现移动赋值重载函数并且自己没有实现析构函数、拷贝构造函数和赋值重载函数。 因此我们需要注意的是移动构造和移动赋值的生成条件与之前六个默认成员函数不同并不是单纯的没有实现移动构造和移动赋值编译器就会默认生成。 默认生成的移动构造函数对于内置类型的成员会完成值拷贝浅拷贝对于自定义类型的成员如果该成员实现了移动构造就调用它的移动构造否则就调用它的拷贝构造。默认生成的移动赋值重载函数对于内置类型的成员会完成值拷贝浅拷贝对于自定义类型的成员如果该成员实现了移动赋值就调用它的移动赋值否则就调用它的赋值重载。 我们实现一个简化版的string来验证默认生成的移动构造和移动赋值重载函数的功能实现。
namespace a
{class string{public://构造函数string(const char* str ){_size strlen(str);_capacity _size;_str new char[_capacity 1];strcpy(_str, str);}//交换两个对象的数据void swap(string s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//拷贝构造函数现代写法string(const string s):_str(nullptr), _size(0), _capacity(0){cout string(const string s) -- 深拷贝 endl;string tmp(s._str);swap(tmp);}//移动构造string(string s):_str(nullptr), _size(0), _capacity(0){cout string(string s) -- 移动构造 endl;swap(s);}//赋值重载函数现代写法string operator(const string s){cout string operator(const string s) -- 深拷贝 endl;string tmp(s);swap(tmp);return *this;}//移动赋值string operator(string s){cout string operator(string s) -- 移动赋值 endl;swap(s);return *this;}//析构函数~string(){//delete[] _str;_str nullptr;_size 0;_capacity 0;}private:char* _str;size_t _size;size_t _capacity;};
}然后我们再编写一个简单的Person类
class Person
{
public://构造函数Person(const char* name , int age 0):_name(name), _age(age){}//拷贝构造函数Person(const Person p):_name(p._name), _age(p._age){}//拷贝赋值函数Person operator(const Person p){if (this ! p){_name p._name;_age p._age;}return *this;}//析构函数~Person(){}
private:a::string _name;int _age;
};
虽然Person类当中没有实现移动构造和移动赋值但拷贝构造、拷贝赋值和析构函数Person类都实现了因此Person类中不会生成默认的移动构造和移动赋值可以通过下面的代码来验证
int main()
{Person s1(张三, 21);Person s2 move(s1); //想要调用Person默认生成的移动构造return 0;
}
上述代码中用一个右值去构造s2对象但由于Person类没有生成默认的移动构造函数因此这里会调用Person的拷贝构造函数拷贝构造既能接收左值也能接收右值这时在Person的拷贝构造函数中就会调用string的拷贝构造函数对name成员进行深拷贝。 如果要让Person类生成默认的移动构造函数就必须将Person类中的拷贝构造、拷贝赋值和析构函数全部注释掉这时用右值去构造s2对象时就会调用Person默认生成的移动构造函数。 Person默认生成的移动构造对于内置类型成员age会进行值拷贝而对于自定义类型成员name因为我们的string类实现了移动构造函数因此它会调用string的移动构造函数进行资源的转移。而如果我们将string类当中的移动构造函数注释掉那么Person默认生成的移动构造函数就会调用string类中的拷贝构造函数对name成员进行深拷贝。 要验证Person类中默认生成的移动赋值函数可以用下面的代码验证方式和上面验证移动构造的方式是一样的。
int main()
{Person s1(张三, 21);Person s2;s2 std::move(s1); //想要调用Person默认生成的移动赋值return 0;
}
类成员变量初始化
默认生成的构造函数对于自定义类型的成员会调用其构造函数进行初始化但并不会对内置类型的成员进行处理。于是C11支持非静态成员变量在声明时进行初始化赋值默认生成的构造函数会使用这些缺省值对成员进行初始化。
class Person
{
public://...
private://非静态成员变量可以在成员声明时给缺省值用于给默认构造函数进行初始化string _name 张三;int _age 20;static int _n; //静态成员变量不能给缺省值
};强制生成默认函数的关键字default
C11可以让我们更好地控制要使用的默认成员函数假设在某些情况下我们需要使用某个默认成员函数但是因为某些原因导致无法生成这个默认成员函数这时可以使用default关键字强制生成某个默认成员函数。下面我们来看一个场景。
class Person
{
public://拷贝构造函数Person(const Person p):_name(p._name), _age(p._age){}
private:string _name; //姓名int _age; //年龄
};
这时就会报错因为Person类中已经有了拷贝构造函数导致无法生成默认构造函数因为默认构造函数生成的条件是没有编写任意类型的构造函数包括拷贝构造函数。
int main()
{Person s; //没有合适的默认构造函数可用return 0;
}
这时我们就可以使用default关键字强制生成默认的构造函数。
class Person
{
public:Person() default; //强制生成默认构造函数//拷贝构造函数Person(const Person p):_name(p._name), _age(p._age){}
private:string _name; int _age;
}; 默认成员函数都可以用default关键字强制生成包括移动构造和移动赋值。 禁止生成默认函数的关键字delete
当我们想限制默认函数生成可以通过如下两种方式
在C98中可以将该函数设置成私有并且只用声明不用定义这样当外部调用该函数时就会报错。在C11中可以在该函数声明后面加上delete表示让编译器不生成该函数的默认版本我们将delete修饰的函数称为删除函数。 例如要让一个类不能被拷贝可以用delete修饰将该类的拷贝构造和赋值重载。
class CopyBan
{
public:CopyBan(){}
private:CopyBan(const CopyBan) delete;CopyBan operator(const CopyBan) delete;
};
注意被delete修饰的函数可以设置为公有也可以设置为私有效果都一样。
继承和多态中final与override关键字
被final修饰的类叫做最终类最终类无法被继承。
class NonInherit final //被final修饰该类不能再被继承
{//...
};
final修饰虚函数表示该虚函数不能再被重写如果子类继承后重写了该虚函数则编译报错。
//父类
class Person
{
public:virtual void Print() final //被final修饰该虚函数不能再被重写{cout hello Person endl;}
};
//子类
class Student : public Person
{
public:virtual void Print() //重写编译报错{cout hello Student endl;}
};
override修饰子类的虚函数检查子类是否重写了父类的某个虚函数如果没有重写则编译报错。
//父类
class Person
{
public:virtual void Print(){cout hello Person endl;}
};
//子类
class Student : public Person
{
public:virtual void Print() override //检查子类是否重写了父类的某个虚函数{cout hello Student endl;}
};