1 C++11之前
1.1 非成员函数或自由函数
1.2 成员函数
1.3 可变参函数
1.4 重载函数
1.5 静态函数
1.6 内联函数
1.7 运算符重载函数
1.8 只读成员函数
1.9 友元函数
1.10 虚成员函数
1.11 特殊成员函数(构造、析构、拷贝、拷贝复制)
1.12 函数模板、类模板、成员模板
2 C++11
2.1 可变参模板函数
2.2 返回值类型后置模板函数
2.3 带override 说明符成员函数
2.4 带final说明符成员函数
2.5 增加的特殊成员函数(移动、移动赋值)
2.6 default 成员函数(显式预置的函数定义)
2.7 delete 成员函数(显式弃置的函数定义)
2.8 delete 其他函数
2.9 lambda 函数
3 C++14
3.1 返回类型自动推导函数
3.2 泛型lambda
4 C++17
4.1 扩展 lambda
4.2 向 lambda 传递 this 的拷贝
4.3 异常声明作为函数类型的一部分
5 C++20
5.1 consteval 函数(立即函数)
5.2 简短的函数模板
5.3 lambda 函数模板
5.4 constexpr 虚成员函数
5.5 协程
6 未来
6.1 Contracts 合约
int add(int a, int b)
{
return a + b;
}
它们是类/结构的一部分。这些也被称为方法(就像在大多数其他面向对象的编程语言中一样),尽管这个术语在C++标准中没有被使用。下面是一个例子:
class math
{
public:
int add(int a, int b)
{
return a + b;
}
};
#include <stdarg.h>
int sum(int count, ...); //原型中使用省略号
int sum(int count, ...){
va_list ap;
va_start(ap, count);
int sum = 0;
for(int i = 0; i < count; i++)
sum += va_arg(ap, int);
va_end(ap);
return sum;
}
int add(int a, int b) {
return a + b;
}
double add(double a, double b) {
return a + b;
}
static int add(int a, int b) {return a + b;}
struct math
{
static int add(int a, int b) {return a + b;}
}
inline int add(int a, int b) {return a + b;}
struct math
{
inline int add(int a, int b);
}
int match::add(int a, int b) {return a + b;}
std::string operator+(std::string const & txt, int n)
{
return txt + std::to_string(n); // channels your JavaScript energy
}
class wrapper
{
public:
wrapper(int a): value_(a) {}
int get() const {return value_;}
private:
int value_;
};
class math
{
int a,b;
public:
math(int a,int b):a(a),b(b){}
friend int add(math m);
};
int add(math m)
{
return m.a + m.b;
}
struct A
{
virtual void f() { std::cout << "A::f()\n"; }
};
struct B : public A
{
virtual void f() { std::cout << "B::f()\n"; }
};
class wrapper
{
public:
wrapper() : value_(0) {}
wrapper(wrapper const & other) {value_ = other.value_; }
wrapper& operator=(wrapper const & other) {if(this != &other) {value_ = other.value_;} }
~wrapper() {}
private:
int value_;
};
template <typename T>
T add(T a, T b)
{
return a + b;
}
template <typename T>
class math1
{
public:
T add(T a, T b)
{
return a + b;
}
};
class math2
{
public:
template <typename T>
T add(T a, T b)
{
return a + b;
}
};
template <typename T>
T add(T a, T b)
{
return a + b;
}
template <typename T, typename ...Ts> // [1]
T add(T t, Ts ... rest) // [2]
{
return t + add(rest...); // [3]
}
auto add(int a, int b) -> int
{
return a + b;
}
template<typename T, typename U>
auto add(T const & a, U const & b) -> decltype(a + b)
{
return a + b;
}
constexpr 函数
template <typename T>
constexpr T add(T a, T b)
{
return a + b;
}
int main()
{
int arr[add(1,2)] = {1,2,3}; // [1]
int a, b;
std::cin >> a >> b;
std::cout << add(a, b) << '\n'; // [2]
}
struct A
{
virtual void f(int) {}
virtual void g() {}
};
struct B : public A
{
void f(int) override {} // OK
void g(char) override {} // error, g() does not override anything
};
struct A
{
virtual void f() {}
};
struct B : public A
{
void f() override (final {}
};
struct C : public B
{
void f() override {} // error, f cannot be overridden anymore
};
struct buffer
{
buffer() // default constructor
:data_(nullptr), size_(0)
{}
explicit buffer(size_t size) // constructor
:data_(new char[size]), size_(size)
{}
~buffer() // destructor
{
delete [] data_;
}
buffer(buffer const & other) // copy constructor
: data_(new char[other.size_])
, size_(other.size_)
{
std::memcpy(data_, other.data_, size_);
}
buffer& operator=(buffer const & other) // copy assignment operator
{
if(this != &other)
{
delete [] data_;
data_ = new char[other.size_];
size_ = other.size_;
std::memcpy(data_, other.data_, size_);
}
return *this;
}
buffer(buffer&& other) // move constructor
: data_(std::move(other.data_))
, size_(other.size_)
{
other.data_ = nullptr;
other.size_ = 0;
}
buffer& operator=(buffer&& other) // move assignment operator
{
if(this != &other)
{
delete [] data_;
data_ = std::move(other.data_);
size_ = other.size_;
other.data_ = nullptr;
other.size_ = 0;
}
return *this;
}
private:
char* data_;
size_t size_;
};
int main()
{
buffer b1;
buffer b2(10);
buffer b3 = b2;
buffer b4 = std::move(b3);
}
struct foo
{
foo(int) {} // user-defined constructor
foo() = default; // compiler generated default constructor
};
struct noncopyable
{
noncopyable() = default;
noncopyable(noncopyable const &) = delete;
noncopyable& operator=(noncopyable const &) = delete;
};
template <typename T>
T add(T a, T b)
{
return a + b;
}
template <>
int add<int>(int a, int b) = delete;
int main()
{
add(1, 2); // error, this specialization is deleted
}
int main()
{
auto add = [](int a, int b) { return a + b; };
add(1, 2);
}
auto add(int a, int b)
{
return a + b;
}
template <typename T, typename U>
auto add(T a, U b)
{
return a + b;
}
int main()
{
using namespace std::string_literals;
auto add = [](auto a, auto b) {return a + b;};
add(1, 2);
add(1.0, 2.0);
add("1"s, "2"s);
}
constexpr lambda,自从 C++17 起,lambda表达式会尽可能的隐式声明 constexpr。
auto squared = [](auto val) { // 自 从C++17起 隐 式constexpr
return val*val;
};
std::array<int, squared(5)> a; // 自 从C++17起OK => std::array<int, 25>
class C {
private:
std::string name;
public:
void foo() {
auto l1 = [*this] { std::cout << name << '\n'; };
}
};
这里,派生类中的成员函数 foo() 和基类中的 foo() 类型不同所以不能重载。这段代码不能通过编译,即使 没有 override 修饰符代码也不能编译,因为我们不能用更宽松的异常声明重载。
class Base {
public:
virtual void foo() noexcept;
};
class Derived : public Base {
public:
void foo() override; // ERROR: 不 能 重 载
//...
};
consteval int add(int const a, int const b)
{
return a + b;
}
int main()
{
constexpr int s1 = add(1, 2); // OK, compile-time evaluation
int a = 12, b = 66;
const int s2 = add(a, b); // error
using fptr = int(int, int);
fptr* padd = add; // error
}
auto add(auto a, auto b)
{
return a + b;
}
auto add = [](auto a, auto b) {return a + b;};
struct magic
{
constexpr virtual int def() const { return 0; }
};
struct programming_magic : public magic
{
constexpr int def() const (override { return 42; }
};
constexpr int initval(magic const & m)
{
return m.def() + 1;
}
int main()
{
constexpr programming_magic pm;
int arr[initval(pm)] = {0};
}
协程,这个是C++20标准的主要特征之一。coroutine是一个具有暂停和恢复能力的函数。不幸的是,C++20只定义了一个执行程序的框架,但并没有定义任何满足这种要求的程序类型。这意味着,我们需要自己编写或者依靠第三方库来实现。这样一个库就是cppcoro库。在C++20中,有三个新的关键字,用于coroutine:co_await,co_return,和co_yield。如果一个函数使用了这三个中的一个,它就会成为一个循环程序。
co_await操作符,用于暂停执行,直到重新开始。
co_return关键字,完成执行并可选返回一个值
co_yield关键字用于暂停执行并返回一个值
#include <cppcoro/generator.hpp>
cppcoro::generator<std::string> produce_items()
{
while (true)
{
auto v = rand();
using namespace std::string_literals;
auto i = "item "s + std::to_string(v);
print_time();
std::cout << "produced " << i << '\n';
co_yield i;
}
}
#include <cppcoro/task.hpp>
cppcoro::task<> consume_items(int const n)
{
int i = 1;
for(auto const& s : produce_items())
{
print_time();
std::cout << "consumed " << s << '\n';
if (++i > n) break;
}
co_return;
}
前提条件(Preconditions):你对输入值的期望/要求是什么?
后置条件(Postconditions):对于输出值,你应该给出什么保证?
不变量(Invariants):你的函数的调用者/使用者期望什么不会改变?
目的(Purpose):你的函数是否有一个明确的目的?
名称(Name):该函数的名称是否反映了它的目的?
参数(Parameters):调用者/用户能轻易混淆它们的含义吗?
前提条件检查:
宽合约函数执行前提条件检查,即检查输入参数值(或程序状态)的有效性。
窄合约函数不执行前提条件检查,即调用者必须确保输入参数(和程序状态)是有效的。
本页共502段,19645个字符,21857 Byte(字节)