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(字节)