C++11 的新特性 ——final override default

发布时间:2024年01月18日

?链接:final 说明符 (C++11 起) - cppreference.com

目录

final的使用

1、不能使用 "final" 修饰符声明非虚函数

2、无法重写基类的“final”函数 "A::foo"

3、不能将“final”类类型用作基类

override 的使用 : 重写父类的虚函数

default 的使用?

?delete 的使用:弃置函数

?两点注意:

实例:

explicit 的使用: 避免隐式转换

??constexpr的使用

enum class 枚举类的使用


final的使用

1、不能使用 "final" 修饰符声明非虚函数

struct Base

{

? ? virtual void foo();

};

struct A : public Base

{

? ? void foo() final; // Base::foo 被覆盖而 A::foo 是最终覆盖函数

? ? void bar() final; // 错误:bar 非虚,因此它不能是 final 的

? ? ? ? ? ? // 不能使用 "final" 修饰符声明非虚函数

};

void A::foo()

{

}

2、无法重写基类的“final”函数 "A::foo"

struct B final : A // struct B 为 final

{

? ? void foo() override; // 错误:foo 不能被覆盖,因为它在 A 中是 final 的

? ? ? ? ? ? // 无法重写“final”函数 "A::foo"

};

3、不能将“final”类类型用作基类

struct C : B{}; // 错误:B 是 final 的

? ? ? ? ? ? //不能将“final”类类型用作基类

override 的使用 : 重写父类的虚函数

? ?C++11标准添加了一个override关键字放在派生类的虚函数后,如果编译器发现派生类重写的虚函数与基类的虚函数不一样(参数或其他不一样的地方),那么编译器将报错

? ? 放在子类重写父类的方法声明的末尾,用来检测重写的方法的正确性

?通过这个功能,便于在项目中查找到对f父类虚函数进行重写时的错误。

default 的使用?

????????声明为default的函数,编译器自动为其生成函数体

class A
{
public:
    // 声明为default的函数,编译器自动为其生成函数体
    A() = default;
    A(const A& a) = default;
    A(int a){}

};

int main()
{
    A a;
    return 0;
}

? ????????class A,没有创建无参构造方法,之所以还可以 直接 “ A a; ”创建对象, 就是因为将A() = default;//声明为default的函数,编译器自动为其生成函数体

?delete 的使用:弃置函数

?参考:函数声明 - cppreference.com

? ?????????如果使用特殊语法?= delete;?取代函数体,那么该函数被定义为显式弃置的。任何弃置函数的使用都是非良构的(程序无法编译)。这包含调用,包括显式(以函数调用运算符)及隐式(对弃置的重载运算符、特殊成员函数、分配函数等的调用),构成指向弃置函数的指针或成员指针,甚至是在不潜在求值的表达式中使用弃置函数。但是可以隐式?ODR 使用刚好被弃置的非纯虚成员函数。

?两点注意:

1、如果函数被重载,那么首先进行重载决议,且只有在选择了弃置函数时程序才非良构

2、已经声明过的函数不能声明为弃置的

实例:

?

// 类A 不允许拷贝,不允许赋值运算符的重载, : 
// thread类就是如此实现的(thread允许移动语义,即夺取某个thread对内存的控制权)
class A
{
public:
    A() = default;

    A(const A& a) = delete; 
    A& operator=(const A& a) =delete;

    // A(const A& a)
    // {
    //     *this = a;
    // }
 
};
int main()
{
    A a;
    // A b(a);  当拷贝构造被声明为delete时,不能在被使用
    return 0;
}

类A的拷贝构造函数已经声明为弃置函数,无法再进行调用

explicit 的使用: 避免隐式转换

????????以阻止不应该允许的经过转换构造函数进行的隐式转换的发生,声明为explicit的构造函数不能在隐式转换中使用。

#include <iostream>
class Test1
{
public :
	Test1(int num):n(num){}
private:
	int n;
};
class Test2
{
public :
	explicit Test2(int num):n(num){}
private:
	int n;
};
 
int main()
{
	Test1 t1 = 12;
	Test2 t2(13);
	//Test2 t3 = 14;//错误:无法从“int”转换为“Test2”
		
	return 0;
}

所以,加上explicit修饰, 指定这个构造器只能被明确的调用/使用, 不能作为类型转换操作符被隐含的使用

??constexpr的使用

? ? ? ?指定变量或函数的值可以在常量表达式中出现

1、实例1

    constexpr int a = 10;   //常量
            // a++;                 //error:表达式必须是可修改的左值
    constexpr int b = 3.14 * 10;   //常量
    std::cout<<b<<std::endl;
    int c = 31;
    switch (c)
    {
    case b:     //constexpr修饰的变量,可以当作常量值使用
        std::cout<<b<<std::endl;
        break;
    default:
        break;
    }

2、实例2

    int x = 42;
    constexpr int size = x;  //此时会报错:表达式必须含有常量值C/C
    int a[size]; 

3、实例3

    //变量在运行时,进行赋值
    int x = 20;
    int y = 12;
    // std::array<int,sum(x,y)> a1;    //报错:表达式必须含有常量值
    
    //模板在编译器时确定
    //方法在运行时调用
    std::array<int,sum(1,2)> a2;

enum class 枚举类的使用

?优点:参考C++11枚举类——enum class-CSDN博客

1、降低命名空间污染

2、避免隐式类型转换

3、可以前置声明

文章来源:https://blog.csdn.net/weixin_70822378/article/details/135653332
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。