101 - C/C++
26 May 2017-
C++ 有两类创建对象的方式: 1). 分配在栈上 2). 分配在堆上
class Foo: public Bar { public: Foo() { std::cout << "Empty constructor" << std::endl; } Foo(const Foo&) { std::cout << "Copy constructor" << std::endl; } Foo(const char* str) { std::cout << "char constructor: " << str << std::endl; } ~Foo() { std::cout << "destructor" << std::endl; } }; // 对象分配在在栈上, 当离开该作用域时, 会自动 delete 该对象 Foo foo; // 调用 Empty constructor Foo foo {}; // 同上 Foo foo = {} // 同上 Foo foo("test"); // 调用带参数的构造方法 Foo foo {"test"}; // 同上 Foo foo = {"test"}; //同上 Foo foo(); // 这是个方法声明, 不是创建对象! // 理论上是先调用了 Empty constructor 然后再调用了 Copy constructor // 不过一般编译器都会进行优化, 所以实际上等价于 Foo foo; Foo foo = Foo(); Foo foo = Foo {}; // 同上 Bar bar = Foo {} // 这里编译器不会优化, bar 的实际类型是 Bar 而不是 Foo! // 对象分配在堆上, 需要自己 delete 该对象 Foo *foo = new Foo(); Foo *foo = new Foo {}; // 同上 delete foo;
new/delete
操作的都是 pointer.Prefer {} initialization over alternatives unless you have a strong reason not to.
Calling constructors in c++ without new
What is difference between instantiating an fooect using new vs. without
C++ default Constructor not being called
Why is list initialization (using curly braces) better than the alternatives?
-
初始化私有的 static 成员变量:
// foo.hpp class Foo { private: static int bar; }; // foo.cpp Foo::bar = 1;
一开始觉得
foo.cpp
访问不到bar
, 觉得应该通过方法初始化, 不过转念一想, 应该和方法一样define
是不受访问控制影响的. -
友元声明在
private
,protected
和public
中没有任何区别.声明为友元的类或方法可以访问该类的私有成员.
Friend declaration in C++ - difference between public and private
-
virtual
相当于 Java 指令里的invokevirtual
.不管一个方法是否被声明成
virtual
, 它都可以被子类override
.当调用一个不是
virtual
的方法时, 调用哪个方法是在编译时就确定的. 相反,virtual
的方法是在运行时决定调用哪个的, 即多态.class Foo { public: void print() { std::cout << "Foo print" << std::endl; } virtual void virtualPrint() { std::cout << "Foo virtual print" << std::endl; } }; class Bar: public Foo { public: void print() { std::cout << "Bar print" << std::endl; } virtual void virtualPrint() { std::cout << "Bar virtual print" << std::endl; } }; Foo *foo = new Bar {}; foo->print(); // Foo print foo->virtualPrint(); // Bar virtual print
-
C++ 中没有
super
的关键字, 通过 namespace 调用父类的方法. 主要还是因为 C++ 支持多继承, 用super
的话会有 MRO 的问题.How to call a parent class function from derived class function?
-
继承时指定的
private
,protected
和public
就是对继承关系的访问控制.Difference between private, public, and protected inheritance
-
A reference can be thought of as a constant pointer (not to be confused with a pointer to a constant value!) with automatic indirection, i.e. the compiler will apply the * operator for you.
但是你还是得把它当成一个对象来用.
Foo& foo = *(new Foo {});
What are the differences between a pointer variable and a reference variable in C++?
make
-
Makefile 由
rules
组成, 语法如下:target ... : prerequisite ... <tab>recipe <tab>...
或者
target ... : prerequisite ... ; recipe <tab>recipe <tab>...
-
make 默认执行第一个名称开头不是
.
的 target.How does “make” app know default target to build if no target is specified?
-
同一个 target 可以出现在多个 rule 中, 只要多条 rule 中的 prerequisite 有一个修改时间晚于 target 那么 recipe 就会被执行. 如果有多个 recipe, 那么只有最后出现的那条 rule 的 recipe 会被执行, 同时会抛出 warning.
但是, 上面说的情况并不是总是成立的:
target 后面如果接的是
::
而不是:
那么这条 rule 被称为 double-colon rule. 如果一个 target 出现在多个 rule 中时这些 rule 必须是相同的类型.如果同一个 target 出现在多个 rule 中, 并且这些 rule 是 double-colon rule 时, 这些 rule 是相互独立的, 只要一条 rule 中的 prerequisite 修改时间晚于 target 那么 recipe 就会被执行.
-
通常变量赋值使用
=
, 这样赋值的变量被称为 recursively expanded variables:foo = $(bar) bar = $(ugh) ugh = Huh? # 输出 Huh? all:;echo $(foo)
GNU make 变量赋值还可以使用
:=
或者::=
(::=
是 POSIX 标准), 这样定义的变量被称为 simply expanded variables:x := foo y := $(x) bar x := later
等价于
y := foo bar x := later
-
默认情况下 (不带
-s
选项) make 执行时, 会输出 recipe 执行的命令. 但是如果 recipe 加上@
前缀, 那么命令本身就不会被输出, 对于echo
这种命令很有用.