马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
目次
1、C++根本
IO流
namespace
引用、const
inline、函数参数
重载
2、类和对象
类举例
3、 内存管理
new/delete
对象内存分布
内存走漏
4、继续
继续权限
继续中的构造与析构
菱形继续
1、C++根本
IO流
- #include <iostream>
- #include <iomanip> // 对于setprecision, setw等
- #include <string>
- #include <fstream> // 对于文件操作
- using namespace std;
- int main()
- {
- int num;
- cin >> num; // 输入流
- if (cin.fail())
- {
- cerr << "input not right"; // 标准err输出
- }
- cout << num << endl; // 标准输出
- // 二进制文件读写
- ofstream binfile("test.bin", ofstream::out | ofstream::binary);
- char in[] = "A";
- binfile.write(in, 1);
- binfile.put('B');
- binfile.close();
- ifstream ifile("test.bin", ofstream::in | ofstream::binary); // 直接构造也可以
- ifile.seekg(0, ifile.end); // 跳转到文件末尾
- int length = ifile.tellg(); // 获取当前字符在文件当中的位置,即文件的字符总数
- ifile.seekg(0, ifile.beg); // 重新回到文件开头
- char data[1024];
- ifile.read(data, length); // 将文件当中的数据全部读取到字符串data当中
- cout << data << endl;
- ifile.close(); // 关闭文件
- ofstream outFile("example.txt"); // 只读,创建 ofstream 对象
- if (!outFile)
- {
- std::cerr << "Unable to open file for writing";
- return 1; // 返回错误代码
- }
- outFile << "hello" << endl;
- outFile << "test" << endl;
- outFile.close();
- ifstream input("example.txt"); // 只读
- if (!input)
- {
- cerr << "Unable to open file";
- return 1;
- }
- std::string line;
- while (std::getline(input, line))
- {
- std::cout << line << std::endl;
- }
- input.close(); // 关闭文件
- fstream file("example.txt", std::ios::in | std::ios::out | std::ios::app);
- file << "\nAppending this line to the file." << std::endl;
- file.seekg(0, std::ios::beg);
- // 从文件读取数据并输出到控制台
- std::string line1;
- while (std::getline(file, line1))
- {
- std::cout << line1 << std::endl;
- }
- file.close(); // 关闭文件
- return 0;
- }
复制代码 std::endl 等效于插入换行符后调用std::cout.flush(),每次革新都会欺凌将缓冲区数据写入到输出装备,但是大概会触发体系调用,用户态和内核空间的切换带来额外开销影响性能。
namespace
- #include <iostream>
- using namespace std;
- namespace A
- {
- int a=1;
- } // namespace A
- namespace B
- {
- int a=2;
- namespace C
- {
- struct T
- {
- int a=4;
- char c;
- };
- int a=3;
- } // namespace C
- }; // namespace B
- int main()
- {
- cout<<"A::a "<<A::a<<"; B::a "<<B::a<<"; C::a "<<B::C::a<<endl;
- B::C::T t1;
- cout<<t1.a<<endl;
- using B::C::T;
- T t2;
- cout<<t2.a<<endl;
- bool F=true;
- cout<<boolalpha<<F<<endl; //noboolalpha 输出1
- int a=1,b=2,c=3;
- auto max = (a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c);//三目运算
- (a<b? a : b)= 30;//C中的三目运算符返回的是变量值,不能作为左值使用.而C++则可以在任意地方
- return 0;
- }
复制代码 引用、const
- #include <iostream>
- using namespace std;
- struct A
- {
- int a;
- char c;
- };
- void show(A *p)
- {
- cout << "show func 指针调用前" << endl;
- cout << p->a << "\t" << p->c << endl;
- p->a = 20;
- cout << "show fun 指针修改调用后" << endl;
- cout << p->a << "\t" << p->c << endl;
- }
- void show1(A &p)
- {
- cout << "show1 引用调用前" << endl;
- cout << p.a << "\t" << p.c << endl;
- p.a = 35;
- cout << "show1 引用修改调用后" << endl;
- cout << p.a << "\t" << p.c << endl;
- }
- void show2(A p)
- { // 临时变量实参的一份拷贝,修改对实参没有影响
- cout << "show2 传值调用前" << endl;
- cout << p.a << "\t" << p.c << endl;
- p.a = 45;
- cout << "show2 传值修改调用后" << endl;
- cout << p.a << "\t" << p.c << endl;
- }
- // 指针所指向的内存空间,不能被修改
- int operA(const A *p)
- {
- // p->a=10;
- return 0;
- }
- // 指针变量本身不能被修改
- int operatorA1(A *const pT)
- {
- pT->a = 10;
- // pT = NULL; //
- return 0;
- }
- // 指针变量和所指的值都不可以改变
- int operatorA2(const A *const pT)
- {
- // pT->a = 10;
- // pT = NULL; //
- cout << "A!" << endl;
- return 0;
- }
- // 数据交换, 值交换无法完成
- void myswap(int i, int j)
- {
- int c = 0;
- c = i;
- i = j;
- j = c;
- }
- // 数据交换, 指针直接对实参修改
- void myswap1(int *i, int *j)
- {
- int c = 0;
- c = *i;
- *i = *j;
- *j = c;
- }
- // 数据交换, 引用交换,引用做函数参数时不用初始化
- void myswap2(int &i, int &j)
- {
- int c = 0;
- c = i;
- i = j;
- j = c;
- }
- // 返回a的本身 a的副本
- int getA1()
- {
- int a = 10;
- return a;
- }
- /*想让引用返回可以用就需要将变量生命为static的
- /*当函数返回值为引用时若返回栈变量不能成为其它引用的初始值
- 不能作为左值使用若返回静态变量或全局变量可以成为其他引用的初始值
- 即可作为右值使用,也可作为左值使用*/
- int &getA2()
- {
- int a = 20;
- // warning: reference to local variable ‘a’ returned [-Wreturn-local-addr]
- return a;
- }
- int *getA3()
- {
- int a = 30;
- // warning: reference to local variable ‘a’ returned
- return &a;
- }
- int main()
- {
- // const operatorA*
- const int x = 0;
- int const y = 2;
- // x=3; y=2;//两个定义一样的效果,修改报错assignment of read-only variable 'x'
- // int const z; //未被初始化 error: uninitialized 'const z
- // 引用
- int var = 10;
- int &temp = var; // 引用需要初始化,像一个常量,有自己的空间sizeof与指针一样
- temp = 12; // 变量的别名
- cout << "var: " << var << " " << temp << endl; // 修改引用同修改本身 12 12
- int temp1 = 10, temp2 = 110;
- cout << "berfor myswap temp1: " << temp1 << " temp2: " << temp2 << endl;
- myswap(temp1, temp2); // 数据交换, 值交换无法完成
- cout << "after myswap temp1: " << temp1 << " temp2: " << temp2 << endl;
- myswap1(&temp1, &temp2); // 指针传入交换
- cout << "after myswap temp1: " << temp1 << " temp2: " << temp2 << endl;
- myswap2(temp1, temp2); // 引用的本质时间接修改实参,编译器创造了指针然后修改
- // 间接赋值的三个条件,1)定义两个变量,2)变量之间建立关联,3)形参间接修改实参;引用是后两个条件合二为一
- cout << "after myswap temp1: " << temp1 << " temp2: " << temp2 << endl;
- cout << " ----复杂类型引用 学习---- " << endl;
- A t = {101, 'A'}; // 结构体 列表初始化
- cout << "main调用指针调用前" << endl;
- cout << t.a << "\t" << t.c << endl; // 101 A
- show(&t);
- cout << "main调用指针调用后" << endl;
- cout << t.a << "\t" << t.c << endl;
- show1(t);
- cout << "main引用调用后" << endl;
- cout << t.a << "\t" << t.c << endl;
- show2(t);
- cout << "main传值调用后" << endl;
- cout << t.a << "\t" << t.c << endl;
- cout << "------函数返回值是一个引用-------" << endl;
- int ga = 1;
- int ga1 = 2;
- ga = getA1();
- // ga1=getA2(); //引用相当于指针,临时变量返回易出错。因为值被释放了
- // int &ga2=getA2(); //栈变量返回不能作为初始值
- cout << "ga: " << ga << endl;
- int *p = NULL; // 指针可以为null
- // p = getA3();
- // cout << *p << endl; // 证明了引用和指针一样,返回临时变量的指针,有可能被释放了再去使用出现异常
- return 0;
- }
复制代码 C++有了指针为什么还要引入引用,明显指针可以办理这些标题?
引入引用的直接缘故原由是提供一种更安全、更简便的间接访问机制
- void func(const complex* x,complex* y){
- complex z=*x+*y; //丑陋,有时需要判空
- }
- void func1(const complex& x, complex& y){
- complex z=x+y;
- }
复制代码 inline、函数参数
- #include <iostream>
- using namespace std;
- #define MYFUNC(a,b)((a)<(b)?(a):(b))
- inline void printA()
- {
- int a = 10;
- cout << "a:" << a << endl;
- }
- inline int Myfun(int a,int b){
- return a<b?a:b;
- }
- struct A
- {
- char c;
- int a;
- };
- void show(const A &m)
- {
- // m.c=10; // error: assignment of member 'A::c' in read-only object
- cout << m.a << endl;
- }
- //函数占位参数 函数调用时,必须写够参数
- void func1(int a,int b, int){
- cout<<"a: "<<a<<" b: "<<b<<endl;
- }
- //默认参数与占位参数
- void func2(int a,int b, int=0){
- cout<<"a: "<<a<<" b: "<<b<<endl;
- }
- // void func3(int a=0,int b){ ////在默认参数规则 ,如果默认参数出现,那么右边的都必须有默认参数
- // }
- int main()
- {
- int a = 10;
- int &b = a; // 普通引用必须初始化
- // int &c=10; //字面值不可以,引用要取地址
- int x = 12;
- const int &y = x; // 让变量引用只读属性不能通过y修改x
- // y=20; 不能修改, x可以改变
- x = 13; //修改值y也变了
- // 常引用的初始化可以用变量或者常量值
- {
- const int a = 10;
- // int &m=11;
- const int &m = 40;
- }
- A t = {'1', 1};
- show(t);
- cout<<" ----inline--------"<<endl;
- printA();//与下相同
- // {
- // int a = 10;
- // cout<<"a"<<a<<endl;
- // }
- ////C++编译器直接将函数体插入在函数调用的地方
- //内联函数省去了普通函数调用时压栈,跳转和返回的开销
- int a1=1, b1=3;
- int c=MYFUNC(a1,b1);
- int d=Myfun(a1,b1);
- cout<<" define: a1: "<<a1<<" b1: "<<b1<<" c: "<<c<<endl;
- cout<<" inlice: a1: "<<a1<<" b1: "<<b1<<" d: "<<d<<endl;
- //int c1=MYFUNC(++a1,b1); //a=3 b=3 c=3
- //==>宏替换并展开 ((++a) < (b) ? (++a) : (b)) //a=3 b=3 c=3
- // cout<<" define ++: a1: "<<a1<<" b1: "<<b1<<" c1: "<<c1<<endl;
- int d1=Myfun(++a1,b1); //a=2 b=3 c=2
- cout<<" inlice ++: a1: "<<a1<<" b1: "<<b1<<" d: "<<d1<<endl;
- func1(a,b,c); //占位符必须有参数
- func2(a,b); //ok
- func2(a,b,c); //ok
- return 0;
- }
复制代码 重载
- #include <iostream>
- using namespace std;
- int func(int x)
- {
- return x;
- }
- int func(int x, int y)
- {
- return x + y;
- }
- // 函数重载 和 函数默认参数 在一起
- // int func(int x, int y, int c = 0)
- // {
- // return x + y + c;
- // }
- auto func(const string &s)
- {
- return s.size();
- }
- // void func(int x,int y){ //函数返回值不是函数重载的判断标准
- // x= x+y;
- // cout<<x<<endl;
- // }
- void func(string *s1, string *s2)
- {
- cout << *s1 << "\t" << *s2 << endl;
- }
- // 定义一个函数类型
- typedef int(myfun)(int a, int b);
- myfun *f = nullptr; // 定义函数指针,指向函数入口
- // 声明一个函数指针类型
- typedef int (*myfunc1)(int a, int b);
- //myfunc1 fp = nullptr;
- // 定义一个函数指针 变量
- void (*myVarPFunc)(int a, int b);
- int main()
- {
- int a = 0;
- a = func(1);
- cout << "func a: " << a << endl;
- // a=func(1,2); //重载与默认参数在一起产生了二义性
- cout << "func1 a: " << a << endl;
- cout << "func2 a: " << func("abcd") << endl;
- string s = "abcde";
- string s1 = "hjic";
- func(&s, &s1);
- myfunc1 fp;
- fp = func;
- cout<<fp(1,3)<<endl;
- return 0;
- }
复制代码 2、类和对象
类举例
- #include <iostream>
- #include <string>
- class Student {
- private:
- std::string name; // 学生姓名
- int age; // 学生年龄
- public:
- // 默认构造函数
- Student() : name("Unknown"), age(0) {
- std::cout << "Default constructor called.\n";
- }
- // 带参数的构造函数
- Student(const std::string& name, int age) : name(name), age(age) {
- std::cout << "Parameterized constructor called for " << name << ".\n";
- }
- // 拷贝构造函数
- Student(const Student& other) {
- this->name = other.name; // 使用 this 指针
- this->age = other.age; // 使用 this 指针
- std::cout << "Copy constructor called for " << this->name << ".\n";
- }
- // 拷贝赋值运算符
- Student& operator=(const Student& other) {
- if (this != &other) { // 防止自我赋值
- this->name = other.name; // 使用 this 指针
- this->age = other.age; // 使用 this 指针
- std::cout << "Copy assignment operator called for " << this->name << ".\n";
- }
- return *this; // 返回当前对象的引用
- }
- // 析构函数
- ~Student() {
- std::cout << "Destructor called for " << name << ".\n";
- }
- // 显示学生信息
- void display() const {
- std::cout << "Name: " << name << ", Age: " << age << "\n";
- }
- };
- int main() {
- // 使用默认构造函数
- Student student1;
- student1.display();
- // 使用带参数的构造函数
- Student student2("Alice", 20);
- student2.display();
- // 使用拷贝构造函数
- Student student3 = student2; // 调用拷贝构造函数
- student3.display();
- // 使用拷贝赋值运算符
- Student student4;
- student4 = student2; // 调用拷贝赋值运算符
- student4.display();
- return 0;
- }
复制代码 3、 内存管理
new/delete
- #include <iostream>
- #include <cstdlib> // 包含 malloc 和 free 的头文件
- class MyClass {
- public:
- MyClass() {
- std::cout << "MyClass constructor called.\n";
- }
- ~MyClass() {
- std::cout << "MyClass destructor called.\n";
- }
- };
- int main() {
- // 使用 new 和 delete
- std::cout << "Using new and delete:\n";
- MyClass* obj1 = new MyClass(); // 使用 new 分配内存
- delete obj1; // 使用 delete 释放内存
- // 使用 malloc 和 free
- std::cout << "\nUsing malloc and free:\n";
- // 注意:malloc 只分配内存,不调用构造函数
- MyClass* obj2 = (MyClass*)malloc(sizeof(MyClass)); // 使用 malloc 分配内存
- if (obj2) {
- new (obj2) MyClass(); // 手动调用构造函数
- }
- // 使用 free 释放内存,但需要手动调用析构函数
- if (obj2) {
- obj2->~MyClass(); // 手动调用析构函数
- free(obj2); // 使用 free 释放内存
- }
- return 0;
- }
复制代码 对象内存分布
- #include <iostream>
- #include <string>
- class MyClass {
- public:
- int value;
- MyClass(int v) : value(v) {
- std::cout << "constructor called for value: " << value << "\n"; //10
- }
- ~MyClass() {
- std::cout << "destructor called for value: " << value << "\n";
- }
- };
- // 全局变量,存储在数据区
- MyClass globalObj(10);
- int main() {
- // 栈区对象
- MyClass stackObj(20);
- std::cout << "Address of stackObj: " << &stackObj << "\n"; //10
- // 堆区对象
- MyClass* heapObj = new MyClass(30);
- std::cout << "Address of heapObj: " << heapObj << "\n";
- // 数据区对象
- std::cout << "Address of globalObj: " << &globalObj << "\n";
- // 程序区(代码区)对象
- std::cout << "Address of main function: " << (void*)main << "\n";
- // 释放堆区对象
- delete heapObj;
- /*
- constructor called for value: 10
- constructor called for value: 20
- Address of stackObj: 0x6963bffbd4
- constructor called for value: 30
- Address of heapObj: 0x22296241640
- Address of globalObj: 0x7ff6cc537030
- Address of main function: 0x7ff6cc531450
- destructor called for value: 30
- destructor called for value: 20
- destructor called for value: 10
- */
- return 0;
- }
复制代码 内存走漏
- #include <iostream>
- class MyClass {
- public:
- MyClass() {
- std::cout << "MyClass constructor called.\n";
- }
- ~MyClass() {
- std::cout << "MyClass destructor called.\n";
- }
- };
- void createMemoryLeak() {
- MyClass* obj = new MyClass(); // 动态分配内存
- // 忘记释放内存,导致内存泄漏
- }
- void createNoMemoryLeak() {
- std::unique_ptr<MyClass> obj = std::make_unique<MyClass>(); // 使用智能指针
- // 不需要手动释放内存,智能指针会自动管理
- }
- int main() {
- for (int i = 0; i < 5; ++i) {
- createMemoryLeak(); // 每次调用都会造成内存泄漏
- }
- std::cout << "Memory leak has occurred.\n";
- for (int i = 0; i < 5; ++i) {
- createNoMemoryLeak(); // 不会造成内存泄漏
- }
- return 0;
- }
复制代码 4、继续
继续权限
继续中的构造与析构
- #include <iostream>
- #include <cstring>
- using namespace std;
- /*
- 1、子类对象在创建时会首先调用父类的构造函数
- 2、父类构造函数执行结束后,执行子类的构造函数
- 3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
- 4、析构函数调用的先后顺序与构造函数相反
- */
- class Object
- {
- public:
- Object(int a, int b)
- {
- this->a = a;
- this->b = b;
- cout<<"object构造函数 执行 "<<"a"<<a<<" b "<<b<<endl;
- }
- ~Object()
- {
- cout<<"object析构函数 \n";
- }
- protected:
- int a;
- int b;
- };
- class Parent : public Object
- {
- public:
- Parent(int p) : Object(1, 2)
- {
- this->p = p;
- cout<<"父类构造函数..."<<p<<endl;
- }
- ~Parent()
- {
- cout<<"析构函数..."<<p<<endl;
- }
- void printP(int a, int b)
- {
- cout<<"我是爹..."<<endl;
- }
- protected:
- int p;
-
- };
- class child : public Parent
- {
- public:
- child(int p) : Parent(p) , obj1(3, 4), obj2(5, 6)
- {
- this->p = p;
- cout<<"子类的构造函数"<<p<<endl;
- }
- ~child()
- {
- cout<<"子类的析构"<<p<<endl;
- }
- void printC()
- {
- cout<<"我是儿子"<<endl;
- }
- protected:
- int p;
- Object obj1;
- Object obj2;
- };
复制代码 菱形继续
- #include <iostream>
- // 基类
- class Base {
- public:
- void show() {
- std::cout << "Base class show function called.\n";
- }
- };
- // 派生类 A
- class DerivedA : public Base {
- public:
- void show() {
- std::cout << "DerivedA class show function called.\n";
- }
- };
- // 派生类 B
- class DerivedB : public Base {
- public:
- void show() {
- std::cout << "DerivedB class show function called.\n";
- }
- };
- // 最终派生类 C
- class DerivedC : public DerivedA, public DerivedB {
- public:
- void show() {
- std::cout << "DerivedC class show function called.\n";
- }
- };
- int main() {
- DerivedC obj;
- // 调用 DerivedC 的 show 方法
- obj.show(); // 输出 DerivedC 的 show 方法
- // 访问基类的 show 方法
- obj.DerivedA::show(); // 明确调用 DerivedA 的 show 方法
- obj.DerivedB::show(); // 明确调用 DerivedB 的 show 方法
- return 0;
- }
复制代码 在菱形继续中,DerivedC 通过 DerivedA 和 DerivedB 都继续了 Base 类的成员。假如不明白指定,编译器无法确定应该调用 DerivedA 还是 DerivedB 中的 Base 类成员,这就导致了二义性。
假如加virtual就可以访问基类的 show 方法 obj.Base::show(); // 通过虚继续,只有一个 Base 的实例 。
|