写了两周stdlibc++.纪录点对c++的理解吧.
constructor 是不能被定义在class外的
当constructor被定义为default, compiler 会生成一个implicity declared constructor, calls the default constructors of the bases and of the non-static members of this class.
当user没有定义copy ctor的时候, compiler 会生成一个implicity declared的版本.
这个implicity的版本在一定情况下会被delete,详情见cppreference.
Substitution failure is not an error - 编译器不会立刻炸,会搜索next
类型擦除(把原来的类型去掉,换成统一类型,换言之cast)
1
2
3
4
char a[10];
void* ap = (void*)a;
int b;
void* bp = (void*)&b;
这里就都cast成了void指针。
再来看个Any的例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Any {
public:
Any() : ptr(nullptr) {}
Any(const Any& other) {
ptr = other.ptr->Copy();
}
Any& operator=(const Any& other) {
this->~Any();
ptr = other.ptr->Copy();
return *this;
}
~Any() {
if (ptr != nullptr) {
delete ptr;
}
}
template<typename T>
void Assign(const T& data) {
this->~Any();
ptr = new Wrapper<T>(data);
}
template<typename T>
T* Get() {
auto wrapper = dynamic_cast<Wrapper<T>*>(ptr);
if (wrapper != nullptr) {
return &wrapper->data;
}
return nullptr;
}
private:
struct AnyData {
virtual ~AnyData() { }
virtual AnyData* Copy() = 0;
};
template<typename T>
struct Wrapper : public AnyData {
Wrapper(const T& data) : data(data) {}
AnyData* Copy() override {
return new Wrapper<T>(data);
}
T data;
};
AnyData* ptr;
};
#include <iostream>
int main() {
Any a;
a.Assign<int>(3);
std::cout << (a.Get<char>() == nullptr) << "\n";
std::cout << (*a.Get<int>() == 3) << "\n";
Any b;
b = a;
std::cout << (*b.Get<int>() == 3) << "\n";
return 0;
}
Placement new
通常的new = malloc + ctor, 所以palcement new 就是在分配好的内存地址上再调用一次ctor
通常的delete = dctor + free
Vtable 的 C 实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#include <stdio.h>
typedef void (*GenericFuncPtr)(void);
//use general ptr array store vf pointer
struct Cat {
GenericFuncPtr* vtable_ptr;
};
void cat_speak(struct Cat* this) {
printf("miao");
}
void cat_die(struct Cat* this) {
printf("ewww");
}
GenericFuncPtr cat_vtable[] = {
// do in the compile time
(GenericFuncPtr)cat_speak,
(GenericFuncPtr)cat_die,
};
void construct_cat(struct Cat* c) {
c->vtable_ptr = cat_vtable;
}
struct Lion {
struct Cat base;
};
void lion_speak(struct Lion* this) {
printf("ow");
}
void lion_die(struct Lion* this) {
printf("ahhh");
}
GenericFuncPtr lion_vtable[] = {
(GenericFuncPtr)lion_speak,
(GenericFuncPtr)lion_die,
};
void construct_lion(struct Lion* l) {
construct_cat(&l->base);
l->base.vtable_ptr = lion_vtable;
}
int main () {
struct Lion l;
struct Cat* c;
construct_lion(&l);
c = &l.base;
// c->speak
((void (*)(struct Lion*))c->vtable_ptr[0])((struct Lion*)c);
// c->die
((void (*)(struct Lion*))c->vtable_ptr[1])((struct Lion*)c);
return 0;
}
Partial specialization 只是针对模版参数,而且function不支持partial specialization.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename _Tp> // primary
class A {
};
template <typename _Tp>
class A<_Tp[]> {
};
template <typename _Tp>
class A<_Tp*> {
};
//template <typename _Tp> //error
//class A<_Tp> {
//};
1
2
3
4
5
6
7
8
9
template<typename T>
struct A {
void Foo(T&& /*rvalue ref*/);
};
struct A {
template<typename T>
void Foo(T&& /*forwarding ref, or `universal ref`*/);
};
//上面的例子虽然T是模板参数,但不是等着被推出来的。
用法与用处。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
template <typename T>
class A {
public:
A() { std::cout << "without size" << "\n"; }
A(size_t size) { std::cout << "with size" << "\n"; }
A(size_t size, size_t idx) { std::cout << "with size, idx" << "\n"; }
~A() { std::cout << "dtor" << "\n"; }
};
template <typename _Tp, typename... Args>
class B : A<_Tp> {
public:
//B() { std::cout << "B ctor" << "\n"; } B<int>b1 wont work;
B(Args&&... _args) : A<_Tp>(_args...) { }
private:
//A<_Tp> _a;
};
class Tmp {
public:
Tmp() { std::cout << "Tmp ctor" << "\n"; }
};
int main () {
//B<int> b1;
B<int,size_t> b2(1);
//B<int,size_t> b(1,2); //error
B<int,size_t,size_t> b3(1,2);
Tmp tmp;
Tmp tmp1(); // function !!!!!!!!!!!!
}