委托构造和继承构造
- 1.委托构造
- 2.using关键字
-
- [2. 命名空间 (Namespace) 的详细注释](#2. 命名空间 (Namespace) 的详细注释)
- [3. 在类继承中使用的详细注释](#3. 在类继承中使用的详细注释)
- [4. 类型别名在模板元编程中的应用(详细注释)](#4. 类型别名在模板元编程中的应用(详细注释))
- [5. 类型别名与函数指针(详细注释)](#5. 类型别名与函数指针(详细注释))
- 关键点总结
1.委托构造
委托构造函数它可以使用当前的类的其他构造函数来协助当前构造函数的初始化操作。
普通构造函数和委托构造函数区别:
- 它们两都是一个成员初始值列表与一函数体;
- 委托构造函数的成员初始值列表只有一个唯一的参数,就是构造函数。
当被委托构造函数当中函数体有代码,那么会先执行完函数体的代码,才加回来到扫托构造函数。
示例
cpp
#include<iostream>
#include<string>
using namespace std;
class A
{
public:
A(int a, string b): _data(a), _str(b)
{
cout << "调用普通构造函数" << endl;
}
//委托构造函数
A(int c):A(c,"yy" )
{
cout << "调用委托构造函数" << endl;
}
void printdata()
{
cout << _data << " " << _str << endl;
}
private:
int _data;
string _str;
};
int main()
{
A obj(20, "xx");
obj.printdata();
A obj2(30);
obj2.printdata();
}
2.using关键字
cpp
好的,以下是带有详细注释的完整代码:
## 1. 类型别名 (Type Aliases)
### 替代 `typedef` 的详细注释
```cpp
#include <iostream>
#include <vector>
#include <map>
// 使用 using 创建类型别名,语法:using 别名 = 原始类型;
using Counter = int; // 给 int 类型起个别名 Counter
using String = std::string; // 给 std::string 起个别名 String
// 函数指针别名:创建一个函数指针类型的别名
// 这个函数接受两个 int 参数,返回 bool
using Comparator = bool(*)(int, int);
// 实际的比较函数
bool compare(int a, int b) {
return a < b;
}
int main() {
// 使用类型别名声明变量
Counter count = 10; // 实际上就是 int count = 10
String name = "Alice"; // 实际上就是 std::string name = "Alice"
// 使用函数指针别名
Comparator comp = compare; // comp 现在指向 compare 函数
std::cout << "比较结果: " << comp(5, 3) << std::endl; // 输出 0 (false),因为 5 < 3 为假
return 0;
}
模板别名的详细注释
cpp
#include <vector>
#include <map>
// 模板类型别名:可以创建带模板参数的类型别名
template<typename T>
using Vec = std::vector<T>; // Vec<T> 等价于 std::vector<T>
template<typename Key, typename Value>
using Map = std::map<Key, Value>; // Map<K,V> 等价于 std::map<K,V>
// 更复杂的模板别名例子
template<typename T>
using Pointer = T*; // Pointer<T> 等价于 T*
int main() {
// 使用模板别名创建容器
Vec<int> numbers = {1, 2, 3, 4, 5}; // 等价于 std::vector<int>
// 使用模板别名创建映射
Map<std::string, int> scores = {
{"Alice", 95},
{"Bob", 87}
}; // 等价于 std::map<std::string, int>
// 使用指针别名
Pointer<int> ptr = new int(42); // 等价于 int* ptr = new int(42)
std::cout << "指针指向的值: " << *ptr << std::endl;
delete ptr; // 释放内存
return 0;
}
2. 命名空间 (Namespace) 的详细注释
引入整个命名空间
cpp
#include <iostream>
#include <vector>
// 使用 using namespace 引入整个 std 命名空间
// 这样在代码中就可以直接使用 std 中的名字,不需要写 std::
using namespace std;
int main() {
// 因为使用了 using namespace std,所以不需要写 std::
vector<int> numbers = {1, 2, 3}; // 而不是 std::vector<int>
cout << "Hello World" << endl; // 而不是 std::cout << "Hello World" << std::endl
return 0;
}
引入特定成员的详细注释
cpp
#include <iostream>
#include <vector>
// 只引入 std 命名空间中的特定成员
// 这样既方便使用,又避免了污染全局命名空间
using std::cout; // 只引入 cout
using std::endl; // 只引入 endl
using std::vector; // 只引入 vector
int main() {
// 可以直接使用引入的成员
vector<int> numbers = {1, 2, 3};
cout << "向量大小: " << numbers.size() << endl;
// 但是其他 std 成员仍然需要 std:: 前缀
// 例如:std::string name; // 这里还需要 std::
return 0;
}
3. 在类继承中使用的详细注释
改变成员访问权限的详细注释
cpp
#include <iostream>
class Base {
private:
int x = 1; // 私有成员,只有 Base 类内部可以访问
protected:
int y = 2; // 保护成员,Base 和派生类可以访问
public:
int z = 3; // 公有成员,任何地方都可以访问
void print() {
std::cout << "Base - x: " << x << ", y: " << y << ", z: " << z << std::endl;
}
};
// Derived 私有继承 Base,所有继承来的成员在 Derived 中都变成 private
class Derived : private Base {
public:
// 使用 using 改变从基类继承来的成员的访问权限
using Base::y; // 将 protected 成员 y 在 Derived 中变为 public
using Base::z; // 将 public 成员 z 在 Derived 中变为 public
using Base::print; // 将 print 方法在 Derived 中变为 public
void show() {
std::cout << "Derived - y: " << y << ", z: " << z << std::endl;
// 注意:x 仍然是 private,不能在这里访问
}
};
int main() {
Derived d;
// 由于使用了 using,这些成员在 Derived 中都是 public
d.y = 20; // 可以访问
d.z = 30; // 可以访问
d.print(); // 可以调用基类的方法
d.show(); // 可以调用派生类的方法
return 0;
}
解决函数隐藏问题的详细注释
cpp
#include <iostream>
class Base {
public:
// 重载的 func 函数
void func() {
std::cout << "Base::func() - 无参数版本" << std::endl;
}
void func(int x) {
std::cout << "Base::func(int): " << x << " - 整数参数版本" << std::endl;
}
};
class Derived : public Base {
public:
// 如果没有下面的 using 声明,Base 的所有 func 重载都会被隐藏
// 使用 using Base::func 将基类的所有 func 重载引入到派生类的作用域
using Base::func;
// 派生类自己的 func 实现
void func() {
std::cout << "Derived::func() - 派生类的实现" << std::endl;
}
// 注意:这里没有覆盖 func(int),但因为有 using,基类的 func(int) 仍然可用
};
int main() {
Derived d;
d.func(); // 调用 Derived::func() - 派生类的版本
d.func(42); // 调用 Base::func(int) - 基类的版本
// 如果没有 using Base::func; 这一行,d.func(42) 会编译错误
// 因为派生类的 func() 会隐藏基类的所有 func 重载版本
return 0;
}
4. 类型别名在模板元编程中的应用(详细注释)
cpp
#include <iostream>
#include <type_traits>
// 主模板:定义 RemovePointer 类型特征
template<typename T>
struct RemovePointer {
using type = T; // 如果 T 不是指针,type 就是 T 本身
};
// 偏特化版本:处理指针类型
template<typename T>
struct RemovePointer<T*> {
using type = T; // 如果 T 是指针,type 就是去掉一层指针后的类型
};
// 使用 using 创建模板别名,简化访问
// RemovePointer_t<T> 等价于 typename RemovePointer<T>::type
template<typename T>
using RemovePointer_t = typename RemovePointer<T>::type;
int main() {
// 测试 RemovePointer_t 类型别名
// int* -> int
RemovePointer_t<int*> value1 = 42; // 实际上是 int value1 = 42
// double** -> double* (只去掉一层指针)
double temp = 3.14;
double* temp_ptr = &temp;
RemovePointer_t<double**> value2 = temp_ptr; // 实际上是 double* value2
std::cout << "value1: " << value1 << std::endl; // 输出 42
std::cout << "value2 指向的值: " << *value2 << std::endl; // 输出 3.14
// 更多例子
RemovePointer_t<int> value3 = 100; // int -> int
RemovePointer_t<float*> value4 = 3.14f; // float* -> float
std::cout << "value3: " << value3 << std::endl; // 输出 100
std::cout << "value4: " << value4 << std::endl; // 输出 3.14
return 0;
}
5. 类型别名与函数指针(详细注释)
cpp
#include <iostream>
#include <vector>
#include <algorithm>
// 创建函数指针类型的别名,提高代码可读性
using Predicate = bool(*)(int); // 谓词函数:接受 int,返回 bool
using Transformer = int(*)(int); // 转换函数:接受 int,返回 int
// 具体的谓词函数:判断数字是否为偶数
bool isEven(int n) {
return n % 2 == 0;
}
// 具体的转换函数:计算平方
int square(int n) {
return n * n;
}
// 处理向量的函数,接受函数指针作为参数
void processVector(std::vector<int>& vec, Predicate pred, Transformer trans) {
std::cout << "处理前的向量: ";
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl;
// 遍历向量,对满足谓词条件的元素应用转换函数
for (auto& item : vec) {
if (pred(item)) { // 如果元素满足谓词条件
item = trans(item); // 对元素应用转换函数
}
}
std::cout << "处理后的向量: ";
for (auto item : vec) {
std::cout << item << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> numbers = {1, 2, 3, 4, 5};
// 使用函数指针别名传递函数
processVector(numbers, isEven, square);
// 处理逻辑:如果是偶数,就计算其平方
// 1(奇数-不变) 2(偶数->4) 3(奇数-不变) 4(偶数->16) 5(奇数-不变)
// 结果:1, 4, 3, 16, 5
return 0;
}
关键点总结
-
类型别名的优势:
- 比
typedef语法更清晰 - 支持模板别名
- 提高代码可读性
- 比
-
命名空间使用的建议:
- 在头文件中避免
using namespace - 在源文件中可以酌情使用
- 优先使用
using std::cout等形式
- 在头文件中避免
-
继承中的 using:
- 解决函数隐藏问题
- 调整成员访问权限
- 保持接口的完整性
-
模板编程:
- 简化复杂类型表达式
- 提高模板代码的可读性
- 与类型特征(type traits)配合使用