第一周的第二节课,讲述了CPP的一些基本用法。
auto关键字允许编译器静态分析推断该类型,而不需要显式声明。
cppint main()
{
auto i = 0; // i is an int
auto j = 8.5; // j is a double
auto k = false; // k is a bool
(void)i;
(void)j;
(void)k;
}
cppint main()
{
// `int` for integers.
auto const meaning_of_life = 42;
// `double` for rational numbers.
auto const six_feet_in_metres = 1.8288;
(void)meaning_of_life;
(void)six_feet_in_metres;
// meaning_of_life++; // COMPILE ERROR HERE
}
使用const关键字有以下几个原因:
cpp#include <catch2/catch.hpp>
TEST_CASE()
{
auto const i = 0;
{
auto d = 0.0;
REQUIRE(d == 0.0);
d = i; // Silent conversion from int to double
CHECK(d == 42.0);
CHECK(d != 41);
}
}
当将int类型的i赋值给double类型的d时,发生了隐式类型转换。i的值为0,在赋值过程中被转换为double类型的0.0。
CHECK(d == 42.0):由于i的值为0,因此在隐式转换后d的值也应该是0.0,而不是42.0。这一行断言会失败。
同样的,CHECK(d != 41);这一行断言也会失败,因为d的值是0.0,与41不相等。
cpp#include <catch2/catch.hpp>
TEST_CASE()
{
auto const i = 0;
{
// Preferred over implicit, since your intention is clear
auto const d = static_cast<double>(i);
CHECK(d == 42.0);
CHECK(d != 41);
}
}
两种定义法都可以,更推荐使用现代语法。
cpp#include <iostream>
auto main() -> int
{
// put "Hello world\n" to the character output
std::cout << "Hello, world!\n";
}
cpp#include <iostream>
int main() {
// put "Hello world\n" to the character output
std::cout << "Hello, world!\n";
}
cpp#include <string>
std::string rgb(short r = 0, short g = 0, short b = 0)
{
(void)r;
(void)g;
(void)b;
return "";
}
int main()
{
rgb(); // rgb(0, 0, 0);
rgb(100); // Rgb(100, 0, 0);
rgb(100, 200); // Rgb(100, 200, 0)
// rgb(100, , 200); // error
}
函数重载是指在同一作用域内,具有相同函数名但参数不同的一组函数。这种技术可以使代码更容易编写和理解。
注意:
建议:
cpp#include <catch2/catch.hpp>
auto square(int const x) -> int
{
return x * x;
}
auto square(double const x) -> double
{
return x * x;
}
TEST_CASE()
{
CHECK(square(2) == 4);
CHECK(square(2.0) == 4.0);
CHECK(square(2.0) != 4);
}
相似点:
不同点:
cpp#include <catch2/catch.hpp>
TEST_CASE()
{
auto i = 1;
auto& j = i;
j = 3;
CHECK(i == 3);
}
常量引用意味着你不能通过该引用修改对象。
但是,对象本身仍然可以被修改,只是不能通过这个常量引用进行修改。
cpp#include <iostream>
int main()
{
auto i = 1;
auto const& ref = i;
std::cout << ref << '\n';
i++; // This is fine
std::cout << ref << '\n';
// ref++; // This is not allowed
auto const j = 1;
auto const& jref = j; // this is allowed
// auto& ref = j; // not allowed
std::cout << jref << "\n";
}
实际参数的值被复制到用于存储形式参数的内存中,在函数调用/执行期间使用。
这意味着在函数内部对参数的任何修改不会影响函数外部的实际参数。
cpp#include <iostream>
auto swap(int x, int y) -> void
{
auto const tmp = x;
x = y;
y = tmp;
}
auto main() -> int
{
auto i = 1;
auto j = 2;
std::cout << i << ' ' << j << '\n'; // prints 1 2
swap(i, j);
std::cout << i << ' ' << j << '\n'; // prints 1 2... not swapped?
}
形式参数仅作为实际参数的别名。每当方法/函数使用形式参数(用于读或写)时,它实际上是在使用实际参数。
优点:
减少内存开销
提高性能
修改原始数据
cpp#include <iostream>
auto swap(int& x, int& y) -> void
{
auto const tmp = x;
x = y;
y = tmp;
}
auto main() -> int
{
auto i = 1;
auto j = 2;
std::cout << i << ' ' << j << '\n'; // 1 2
swap(i, j);
std::cout << i << ' ' << j << '\n'; // 2 1
}
cpp/*auto by_value(std::string const sentence) -> char;
// takes ~153.67 ns
by_value(two_kb_string);
auto by_reference(std::string const& sentence) -> char;
// takes ~8.33 ns
by_reference(two_kb_string);
auto by_value(std::vector<std::string> const long_strings) -> char;
// takes ~2'920 ns
by_value(sixteen_two_kb_strings);
auto by_reference(std::vector<std::string> const& long_strings) -> char;
// takes ~13 ns
by_reference(sixteen_two_kb_strings);*/
声明:
定义:
cpp#include <catch2/catch.hpp>
// 函数声明
void declared_fn(int arg);
// 类声明
class declared_type;
// 这个类是定义的,但不是所有的方法都被定义了。
class defined_type {
int declared_member_fn(double);
int defined_member_fn(int arg) { return arg; }
};
// 函数定义
int defined_fn(int arg)
{
(void)arg;
return 1;
}
TEST_CASE()
{
int i;
int const j = 1;
auto vd = std::vector<double> {};
(void)i;
(void)j;
(void)vd;
}
一般有以下几种错误:
编译时错误是在源代码编译过程中由编译器检测到的错误。常见的编译时错误包括:
链接时错误是在编译器生成目标文件后,由链接器在试图将多个目标文件链接成一个可执行文件时检测到的错误。常见的链接时错误包括:
运行时错误是在程序运行过程中发生的错误。常见的运行时错误包括:
逻辑错误是程序在运行时不会产生错误信息,但程序的输出结果不符合预期。这类错误通常是由于编程逻辑不正确引起的,需要通过调试和测试来发现和修正。
cpp#include <fstream>
#include <iostream>
int main()
{
// Below line only works C++17
std::ofstream fout { "data.out" };
if (auto in = std::ifstream { "data.in" }; in) { // attempts to open file, checks it was opened
for (auto i = 0; in >> i;) { // reads in
std::cout << i << '\n';
fout << i;
}
if (in.bad()) {
std::cerr << "unrecoverable error (e.g. disk disconnected?)\n";
} else if (not in.eof()) {
std::cerr << "bad input: didn't read an int\n";
}
} // closes file automatically <-- no need to close manually!
else {
std::cerr << "unable to read data.in\n";
}
fout.close();
}
本文作者:Jeff Wu
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!