移动语义:
简单地说就是 复制对象或者其他数据的时候 不再是通过创建临时对象,复制构造函数,创建新的对象,删除构造函数这样的方法了
而是将需要新对象的地方(变量)直接指向该数据,而数据本身不做任何移动或者改变。 这需要配合右值引用的使用才可以达到此目的
程序例子
#include <iostream>
using namespace std;
class Useless
{
private:
int n;
char* pc;
static int ct;
void ShowObject() const;
public:
Useless();
explicit Useless(int k);
Useless(int k, char ch);
Useless(const Useless & f);
Useless(Useless && f);
~Useless();
Useless operator+(const Useless & f) const;
void ShowData() const;
};
int Useless:: ct = 0;
Useless::Useless()
{
++ct;
n = 0;
pc = nullptr;
cout << "default constructor called; number of objects: " << ct << endl;
ShowObject();
}
Useless::Useless(int k) : n(k)
{
++ct;
cout <<"int constructor called; number of objects: " << ct << endl;
pc = new char[n];
ShowObject();
}
Useless::Useless(int k, char ch) : n(k)
{
++ct;
cout << "int, char constructor called; number of objects: " << ct << endl;
pc = new char[n];
for (int i = 0; i < n; i++)
pc[i] = ch;
ShowObject();
}
Useless::Useless(const Useless & f): n(f.n)
{
++ct;
cout << "copy const called; number of objects: " << ct << endl;
pc = new char[n];
for(int i = 0; i < n; i++)
pc[i] = f.pc[i];
ShowObject();
}
// 这里是移动构造函数
Useless::Useless(Useless && f): n(f.n)
{
++ct;
cout << "monve constructor called; number of objects: " << ct << endl;
pc = f.pc;
f.pc = nullptr;
f.n = 0;
ShowObject();
}
Useless::~Useless()
{
cout << "destructor called; objects left: " << --ct << endl;
cout << "deleted object:\n";
ShowObject();
delete [] pc;
}
Useless Useless::operator+(const Useless & f) const
{
cout << "Entering operator+()\n";
Useless temp = Useless(n + f.n);
for(int i = 0; i < n; i++)
temp.pc[i] = pc[i];
for(int i = 0; i < temp.n; i++)
temp.pc[i] = f.pc[i - n];
cout << "temp object:\n";
cout << "Leaving operator+()\n";
return temp;
}
void Useless::ShowObject() const
{
cout << "Number of elements: " << n;
cout << " Data address: " << (void *) pc << endl;
}
void Useless::ShowData() const
{
if ( n == 0)
cout << "(object empty)";
else
for(int i = 0; i < n; i++)
cout << pc[i];
cout << endl;
}
int main()
{
Useless one(10, 'X');
Useless two = one;
Useless three(20, 'o');
// 在调用operator+后返回临时对象的时候会调用
// 但不是每个编译器都调用,反正我这里没效果。最后依然用了复制构造函数
Useless four (one + three);
cout << "object one: ";
one.ShowData();
cout << "object two: ";
two.ShowData();
cout << "object three: ";
three.ShowData();
cout << "object four: ";
four.ShowData();
}
我的编译器没出来 嗯。。。突然不想理这个移动构造函数了
移动构造函数可以用在operator=函数中
强行移动
可以使用static_cast<>将对象强行转换成右值
c++11有更简单的方法 <utility>下有个 std::move()函数
程序示例
#include <iostream>
//使用move()函数时需要的头文件
#include <utility>
class Useless
{
private:
int n;
char* pc;
static int ct;
void ShowObject() const;
public:
Useless();
explicit Useless(int k);
Useless(int k, char ch);
Useless(const Useless & f);
Useless(Useless &&f);
~Useless();
Useless operator+(const Useless & f) const;
// 不同时候调用不懂的operator=
Useless & operator=(const Useless & f);
Useless & operator=(Useless && f);
void ShowData() const;
};
int Useless::ct = 0;
Useless::Useless()
{
++ct;
n = 0;
pc = nullptr;
}
Useless::Useless(int k) : n(k)
{
++ct;
pc = new char[n];
}
Useless::Useless(int k, char ch) : n(k)
{
++ct;
pc = new char[n];
for(int i=0; i<n; i++)
pc[i] = ch;
}
Useless::Useless(const Useless & f): n(f.n)
{
++ct;
pc = new char[n];
for(int i=0; i < n; i++)
pc[i] = f.pc[i];
}
Useless::Useless(Useless && f): n(f.n)
{
++ct;
pc = f.pc;
f.pc = nullptr;
f.n = 0;
}
Useless::~Useless()
{
delete [] pc;
}
Useless & Useless::operator=(const Useless & f)
{
std::cout << "copy assignment operator called:\n";
if (this == &f)
return *this;
delete [] pc;
n = f.n;
pc = new char[n];
for(int i = 0; i < n; i++)
pc[i] = f.pc[i];
return *this;
}
Useless & Useless::operator=(Useless && f)
{
std::cout << "move assignment operator called:\n";
if (this == &f)
return *this;
delete [] pc;
n = f.n;
pc = f.pc;
f.n = 0;
f.pc = nullptr;
return *this;
}
Useless Useless::operator+(const Useless & f) const
{
Useless temp = Useless(n + f.n);
for(int i = 0; i < n; i++)
temp.pc[i] = pc[i];
for(int i = n; i < temp.n; i++)
temp.pc[i] = f.pc[i -n];
return temp;
}
void Useless::ShowObject() const
{
std::cout << "Number of elements: " << n;
std::cout << " Data address: " << (void *) pc << std::endl;
}
void Useless::ShowData() const
{
if (n == 0)
std::cout << "(object emopty)";
else
for (int i = 0; i < n; i++)
std::cout << pc[i];
std::cout << std::endl;
}
int main()
{
using namespace std;
Useless one(10, 'x');
Useless two = one + one;
cout << "object one: ";
one.ShowData();
cout << "object tow: ";
two.ShowData();
Useless three, four;
cout << "three = one\n";
// 使用赋值运算符函数
three = one;
cout << "now object three = ";
one.ShowData();
cout << "and object one = ";
one.ShowData();
cout << "four = one + two\n";
// 使用移动赋值运算符函数
four = one + two;
cout << "now object four = ";
four.ShowData();
cout << "four = move(one)\n";
//强制转换成右值
four = std::move(one);
cout << "noew object four = ";
four.ShowData();
cout << "and object one = ";
one.ShowData();
}
如果没有提供移动构造函数的话,编译器会提供一个默认的
也会提供一个默认的移动运算符
默认的方法和禁用的方法
想要显示的指定某个构造函数,赋值构造函数和赋值构造函数等构造函数为默认方法
只需要在函数后面加上“ = default”
Someclass(const Someclass &) = default;
同样 如果要禁止编译器使用特定的方法的话 将‘default’改成“delete”
这个跟 ‘将复制构造函数和赋值运算符放到private部分’的效果一样
default只能用于6种特殊函数 delete全适用
比如:
class Someclass
{
public:
void redo(double);
};
.....
Someclass sc;
sc.redo(5);
// 这时候会将5提升为5.0调用redo()
//但是改成如下
class Someclass()
{
public:
void redo(double);
void redo(int) = delete;
};
//再使用sc.redo(5)则会报编译错误
委托构造函数:
在一个构造函数中调用另一个构造函数,实现代码复用。
这个可以算偷懒么(手动斜眼笑)
继承构造函数
c++98中允许利用命名空间的方式实现继承类调用父类函数
c++11将这种方法用于构造函数中(不包括默认构造函数,复制构造函数和移动构造函数已经与派生类构造函数特征标匹配的构造函数)
示例: 该例子也用了委托构造函数
管理虚函数
override: 用来声明要覆盖一个父类的虚函数
父类:
virtual void f(char ch) const {......} const
子类
virtual void f(char* ch){........} const override
因为子类与父类的虚函数在特征标上不匹配 所以编译器会直接报错
final: 用来标识某个虚函数禁止派生类覆盖
virtual void f(char ch) const final {...};
你们两打一架吧
完结