C++11 の新しいクラスの機能
1. デフォルトのメンバー関数
元の C++ クラスには、6 つのデフォルトのメンバー関数があります。
- コンストラクタ
- デストラクター
- コピーコンストラクター
- コピー代入のオーバーロード
- アドレスのオーバーロードを取る
- constアドレスのオーバーロード
最後になりますが、最初の 4 つは重要ですが、後の 2 つはほとんど役に立ちません。デフォルトのメンバー関数は、記述しないとコンパイラーがデフォルトのメンバー関数を生成します。
C++11 では、移動コンストラクターと移動代入演算子のオーバーロードという 2 つの新しいものが追加されています。
移動コンストラクターと移動代入演算子のオーバーロードについては、次のような注意すべき点がいくつかあります。
- 移動コンストラクターを自分で実装せず、デストラクター、コピー構築、コピー代入のオーバーロードも実装しない場合。その後、コンパイラはデフォルトの移動構造を自動的に生成します。デフォルトで生成された移動コンストラクターは、組み込み型メンバーの場合はメンバーごとにバイトごとのコピーを実行しますが、カスタム型メンバーの場合は、メンバーが移動構築を実装しているかどうかを確認する必要があります。実装している場合は、移動構築を呼び出します。そうでない場合は、copy constructionを呼び出します。
- 移動割り当てのオーバーロードには上記と同じルールがあります
- 移動構築または移動代入を指定した場合、コンパイラーはコピー構築およびコピー代入を自動的には提供しません。
以下のコードは vs2013 では反映できず、上記の機能は vs2019 でのみ実証できます。
namespace phw {
class string {
public:
typedef char *iterator;
iterator begin() {
return _str;
}
iterator end() {
return _str + _size;
}
string(const char *str = "")
: _size(strlen(str)), _capacity(_size) {
//cout << "string(char* str)" << endl;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
// s1.swap(s2)
void swap(string &s) {
::swap(_str, s._str);
::swap(_size, s._size);
::swap(_capacity, s._capacity);
}
// 拷贝构造
string(const string &s)
: _str(nullptr) {
cout << "string(const string& s) -- 深拷贝" << endl;
string tmp(s._str);
swap(tmp);
}
// 移动构造
string(string &&s)
: _str(nullptr) {
cout << "string(string&& s) -- 移动拷贝" << endl;
swap(s);
}
// 赋值重载
string &operator=(const string &s) {
cout << "string& operator=(string s) -- 深拷贝" << endl;
string tmp(s);
swap(tmp);
return *this;
}
// s1 = 将亡值
string &operator=(string &&s) {
cout << "string& operator=(string&& s) -- 移动赋值" << endl;
swap(s);
return *this;
}
~string() {
//cout << "~string()" << endl;
delete[] _str;
_str = nullptr;
}
char &operator[](size_t pos) {
return _str[pos];
}
void reserve(size_t n) {
if (n > _capacity) {
char *tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;
_capacity = n;
}
}
void push_back(char ch) {
if (_size >= _capacity) {
size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
reserve(newcapacity);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
//string operator+=(char ch)
string &operator+=(char ch) {
push_back(ch);
return *this;
}
string operator+(char ch) {
string tmp(*this);
tmp += ch;
return tmp;
}
const char *c_str() const {
return _str;
}
private:
char *_str;
size_t _size;
size_t _capacity;// 不包含最后做标识的\0
};
//const bit::string& to_string(int value)
phw::string to_string(int value) {
bool flag = true;
if (value < 0) {
flag = false;
value = 0 - value;
}
phw::string str;
while (value > 0) {
int x = value % 10;
value /= 10;
str += ('0' + x);
}
if (flag == false) {
str += '-';
}
std::reverse(str.begin(), str.end());
return str;
}
}// namespace phw
// 以下代码在vs2013中不能体现,在vs2019下才能演示体现上面的特性。
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(Person &&p) = default;
Person &operator=(Person &&p) = default;
~Person() {
cout << "~Person()" << endl;
}
private:
phw::string _name;// 自定义类型
int _age = 1; // 内置类型
};
int main() {
Person s1("张三", 18);
Person s2 = s1;
Person s3 = std::move(s1);
cout << endl;
return 0;
}
2. キーワードの削除
delete
キーワードは、一部の特別なメンバー関数または演算子を明示的に無効にして、特定のコンテキストでの呼び出しや使用を防ぐために使用されます。
キーワードを使用するとdelete
、クラスの宣言から次の関数を削除できます。
-
デフォルトのコンストラクターを削除します。
MyClass() = delete;
これにより、デフォルトのコンストラクターが無効になり、引数なしでオブジェクトを作成できなくなります。
-
コピー コンストラクターとコピー代入演算子を削除します。
MyClass(const MyClass&) = delete; MyClass& operator=(const MyClass&) = delete;
これにより、オブジェクトのコピーが禁止されます。つまり、コピー コンストラクターとコピー代入演算子を使用したオブジェクトのコピーが禁止されます。
-
移動コンストラクターと移動代入演算子を削除します。
MyClass(MyClass&&) = delete; MyClass& operator=(MyClass&&) = delete;
これにより、オブジェクトの移動セマンティクスが禁止されます。つまり、オブジェクトの移動操作に対する移動コンストラクターと移動代入演算子の使用が禁止されます。
-
デストラクターを削除します。
~MyClass() = delete;
これにより、オブジェクトの破棄が防止されます。つまり、オブジェクトのメモリを解放するためにデストラクターを呼び出すことが禁止されます。
delete
キーワードを使用すると、コンパイル中に潜在的なエラーや誤った使用法を検出できます。たとえば、削除された関数をコピーまたは移動しようとすると、コンパイラはエラーを生成します。
例:
class MySingleton {
private:
MySingleton() = delete; // 默认构造函数被删除
MySingleton(const MySingleton&) = delete; // 复制构造函数被删除
MySingleton& operator=(const MySingleton&) = delete; // 复制赋值运算符被删除
public:
static MySingleton& getInstance() {
static MySingleton instance;
return instance;
}
void doSomething() {
// 执行操作
}
};
int main() {
MySingleton& singleton = MySingleton::getInstance();
singleton.doSomething();
// 错误示例,尝试创建被删除的默认构造函数的对象
// MySingleton singleton2; // 编译错误
return 0;
}
上記の例では、シングルトン クラスは、デフォルト コンストラクター、コピー コンストラクター、およびコピー代入演算子を削除することによって実装されます。これにより、複製やコピーによって複数のインスタンスが作成されるのを防ぎます。コピーしようとする試みはコンパイル時に捕捉され、エラーが生成されます。
要約すると、C++11 のdelete
キーワードにより、開発者は特定の状況での誤用やエラーを避けるために特定の関数を明示的に削除する柔軟性が向上します。これは、クラスの動作とセマンティクスをより細かく制御できるようにする C++ の強力な機能です。
3. ファイナルとオーバーライド
C++11 標準では、キーワードfinal
と はoverride
クラスの継承と仮想関数の書き換えに使用されます。これらは、継承関係と関数のオーバーライドを制御およびマークするための明示的な方法を提供します。
3.1 決勝
final
キーワードは、クラス、仮想関数、またはメンバー関数を修飾するために使用され、それらが継承またはオーバーライドできないことを示します。具体的には:
- このキーワードをクラスに適用すると、
final
そのクラスが他のクラスに継承できないことを示します。 - このキーワードは、仮想関数に適用されると、
final
その仮想関数が派生クラスによってオーバーライドできないことを示します。 - このキーワードをメンバー関数に適用すると、
final
そのメンバー関数が派生クラスでオーバーライドできないことを示します。
以下にfinal
キーワードの使用例を示します。
class Base final {
// ...
};
class Derived : public Base {
// 错误,无法继承被标记为final的类
// ...
};
class Base {
public:
virtual void foo() const final;
};
class Derived : public Base {
public:
void foo() const override; // 错误,无法重写被标记为final的虚函数
};
class Base {
public:
virtual void foo() const;
};
class Derived : public Base {
public:
void foo() const final; // 错误,无法在派生类中重写被标记为final的成员函数
};
3.2 オーバーライド
override
このキーワードは、派生クラスのメンバー関数を明示的にマークして、それらが基本クラスの仮想関数のオーバーライドされたバージョンであることを示すために使用されます。キーワードを使用すると、override
コードの可読性と保守性が向上し、コンパイラによるエラーの検出が容易になります。派生クラスの関数宣言でoverride
キーワードが使用されているが、基本クラスの仮想関数をオーバーライドしていない場合、コンパイル エラーが発生します。
以下にoverride
キーワードの使用例を示します。
class Base {
public:
virtual void foo() const{
}
};
class Derived : public Base {
public:
void foo() const override{
} // 表示该函数是基类虚函数的重写版本
};
class Base {
public:
virtual void foo() const{
}
};
class Derived : public Base {
public:
void foo() const{
} // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};
キーワードを使用した例override
:
class Base {
public:
virtual void foo() const{
}
};
class Derived : public Base {
public:
void foo() const override{
} // 表示该函数是基类虚函数的重写版本
};
class Base {
public:
virtual void foo() const{
}
};
class Derived : public Base {
public:
void foo() const{
} // 错误,没有使用override关键字重写基类的虚函数,编译器不会报错
};
override
C++11 より前では、仮想関数のオーバーライドは暗黙的であり、キーワードの使用を必要としなかったことに注意してください。ただし、override
キーワードを使用すると、より明示的なセマンティクスが提供され、コンパイル時のエラー検出が向上します。