C++ Zero To One 0.005

1, protected能否被实例对象访问

>* 发现问题
重新实现Vector中, 要对ADT的access进行区别。
protected能否被实例对象访问?
protected能否被继承类访问?
>* 尝试
=================== source code ===========================
class Base {
private:
int i = 0;
void f_priv() {std::cout << "calling f_priv() in private" << std::endl;}
protected:
void f_prot() {std::cout << "calling f_prot() in protected" << std::endl;}
public:
void f() {
std::cout << "calling f() in public" << std::endl;
f_prot();
}
};

class Derived : Base {
public:
void call_f_prot() {f_prot();}
// void call_f_priv() {f_priv();} // private不能被继承类直接访问
};

int main() {
Base b;
Derived d;
// b.f_prot(); // protected成员不能被实例对象直接访问
d.call_f_prot(); // 通过继承类的public成员, 访问基类的protected
// d.call_f_priv();
return 0;
}
=============================================================

>* 特点
protected不会被实例访问, 会被继承类在类中进行访问。

希望用户不能访问到protected中的成员, 但继承类能够访问到。
而private让用户和继承类都不能访问到, 只有友元能访问到。
---------------------------------------------------------------------------------------------

2, for循环语句的简单写法

>* 发现问题
for语句的三个表达式如何写?
Vector(int c = DEAFAULT_CAPACITY, int s = 0, T v = 0)
{_elem = new T[_capacity = c];
for (_size = 0; _size < s; _elem[size++] = v)} // 默认

>* 利用for的参数
for ( declaration-or-expression(optional) ;
declaration-or-expression(optional) ;
expression(optional) )
=================== source code ============================
const int s = 8;
int size = 0;
int elem[s] = {};
/*
for (size = 0; size < s; size++) {
elem[size] = 2;
}
*/
// 第三个参数, 递增size的同时, 给修改elem
for (size = 0; size < s; elem[size++] = 2) {}
// 第三个参数, 修改i的同时, 打印elem[i]对应的元素
for (int i = 0; i < size; std::cout << elem[i++] << std::endl) {}
============================================================
>* 反思
某变量会让循环条件false, 且该变量又是语句中的某一要素时候,一举两得。
----------------------------------------------------------------------------------------------

3, T const&, const T&, T& const, T const*, const T*, T* const 辨析

>* 发现问题
=================== source code ============================
Vector(T* const A, Rank lo, Rank hi) // 数组区间复制
Vector(Vector<T> const& V, Rank lo, Rank hi) // 向量区间复制
============================================================
对上述代码中的 Vector<T> const& V不理解, 为什么const& 跟在type之后? 它是否表达常量引用?

>* 常量引用
type const&, type& const之间是什么区别 ?
先回答: 没区别。 但偏向写成前者, 能直接看出这是一个引用类型, 且为常量引用.

让测试代码跑跑。
=================== source code =============================
int f() {
int a = 0, b = 1;
const int ca = 0, cb = 1;

int& ref_a = a; // ref_a是整数a的引用类型
int* ptr_a = &a; // ptr_a是指向整数a的指针
const int* ptr_ca = &ca; // ptr_ca是指向常量整型的指针
const int* const cptr_ca = &ca; // cptr_ca是指向常量整型的常量指针
int const& cref_a = a; // cref_a是对整型的常量引用?
const int& cref_a_1 = ca; // cref_a_1是对整型常量引用?
// const int& const cref_a_2 = ca; // 对整型常量的常量引用?
// const int const& cref_a_3 = ca; // 还是这样? 对整型常量的常量引用?
// 引用不能duplicate const
f1(cref_a); // 将cref_a传入f1(), cref_a类型为 int const&匹配
// cref_a++; // read-only // 两者都是常量引用
// cref_a_1++; // read-only

// 引用指针
int* const& cref_ptra = ptr_a; // 对整型指针的常量引用
// int const& cref_ptra_1 = ptr_a; // 错误: 引用对象类型int*
const int* const& cref_ptrca = ptr_ca; // 对指向常量指针的常量引用
// int* const& cref_ptrca_1 = ptr_ca; // 错误: 引用对象类型const int*
const int* const& cref_cptrca = cptr_ca;

(*cref_ptra)+=1; // cref_ptra整型指针的常量引用, 改变指向整型
// (*cref_cptrca)+=1; // ERROR: 无法通过引用, 改变指向常量的常量指针指向的整数(常量)
}

void f1(int const& ic) {
std::cout << "calling f1()...\n";
}
=============================================================

常量引用的写法. 所引用的对象类型为type
(type) const& ref_t;
// const&写在右边是因为侧重于表明其常量指针

另外, 这一type可以是int, const int, int*, const int*等等

>* 常量指针
===================== source code ===========================
int a = 0, b = 0, c = 0, d = 0;
int* p_a = &a; // 指向int的指针
// 指针地址可变, 指向的a可变
(*p_a)++; p_a = &b;
std::cout << "*p_a = " << *p_a << ", a = " << a << std::endl;
const int* p_b = &b; // 指向const int的指针
// 指针地址可变, 指向的元素转换成const不可变
// (*p_b)++;
p_b = &c;
std::cout << "*p_b = " << *p_b << ", b = " << b << std::endl;
int* const cp_c = &c; // 指向int的const指针
// 指针地址不可变, 指向的元素可以变
(*cp_c)++;
// cp_c = &d;
std::cout << "*cp_c = " << *cp_c << ", c = " << c << std::endl;
// int const* cp_c1 = &c; // 指向const int的指针, 仍采用上种方法
const int* const cp_cd = &d; // 指向const int的const指针
// 指针地址不可变, 指向值不可变
// (*cp_cd)++;
// cp_cd = &a;
std::cout << "*cp_cd = " << *cp_cd << ", d = " << d << std::endl;
------------------------ ./a.out ---------------------------
*p_a = 0, a = 1
*p_b = 0, b = 0
*cp_c = 1, c = 1
*cp_cd = 0, d = 0
============================================================
T* = &a; // 指针
const T* = &ca; // 指向常量的指针
T* const = &a; // 常量指针, 指针地址不可变
const T* const = &ca; // 指向常量的常量指针, 指向值和指针地址都不可变

>* const_cast<type>();
=======
int b = 0;
const int* p_b= &b;
*(const_cast<int*>(p_b))+=1; // 这种方式可以让b递增1
// (*p_b)++ // const_cast只是一个临时操作
==========
一方面可以去掉const的性质, 另外一方面又是临时的, 可以确保安全。
我想这可能会用在, 绝大多数是const, 只有极少情况才会变的数据类型中。

>* 最初的辨析
T const& : 引用, T类型的常量引用, 该引用不会被修改
const T& : 同上, 只是不同写法。现在偏向用上面那种
T& const : 非法
T const* : 指针, 指向常量T的指针, const T*相同
const T* : 指针, 指向常量T的指针, 我偏向用这种
T* const : 指针, 指向T的常量指针
---------------------------------------------------------------------------------------