C++
来源:互联网 发布:moonlight软件 编辑:程序博客网 时间:2024/06/06 18:49
本文是本人学习C plus plus的笔记。内容概况可以查看目录结构。
Visual Studio 2017使用快捷键
- F1:光标放在方法上面,进入该方法的web详细信息。
- F12:方法的源码。
- Ctrl+Blank:只能提示。
- Ctrl+Shift:函数参数提示。
- Ctrl+Tab:窗口切换。
- Shift+Alt +Enter:全屏。
复制构造函数
1、形式X::X(x&) 或者X::X(const X&), 不允许有X::X(X)的复制构造函数, 否则无法编译通过。
2、起作用的三种情况
(1)当用一个对象去初始化同类的另一个对象的时候。
(2)如果某函数有一个参数是类A的对象,那么该函数被调用时,类A的复制构造函数将被调用。如果参数是引用,则不会调用复制构造函数。
(3)如果函数的返回值是类A的对象的时候,函数返回时,A的复制构造函数被调用。如果返回值是引用,则不会调用复制构造函数。
3、使用情况:
其中,当需要函数返回值是对象(比如集合)的副本的时候,可以使用复制构造函数。
例子1:
因为Func函数的参数是A的对象,所以当调用函数Func的时候,就会调用A的复制构造函数。
#include <iostream>using namespace std;class A {public: A() { cout << "default constructor" << endl; } A(A& a) { //复制构造函数 cout << "copy constructor called" << endl; }};void Func(A a1) {}int main(int argc, char* args[]) { A a2; Func(a2); system("pause"); return 0;}
执行结果为:
default constructorcopy constructor called
例子2
#include <iostream>using namespace std;class A {public: int b = 1; A() { cout << "default constructor" << endl; b = 2; } A(A& a) { cout << "copy constructor called" << endl; }};void Func(A a1) { //这里面的a1没有经过A类的构造函数。 cout << a1.b << endl;}int main(int argc, char* args[]) { A a2; a2.b = 5; Func(a2); system("pause"); return 0;}
执行结果为:
default constructorcopy constructor called1
示例3:
函数Func的返回值是A对象,会调用复制构造函数。
#include <iostream>using namespace std;class A {public: int b = 1; A() { cout << "default constructor" << endl; b = 2; } A(A& a) { cout << "copy constructor called" << endl; }};A Func() { A a; a.b = 5; return a;}int main(int argc, char* args[]) { A a = Func(); cout << a.b << endl; system("pause"); return 0;}
执行结果
default constructorcopy constructor called1
一个相对复杂一点的实例,包含了复制构造函数、析构函数、重载操作符等,类的作用是能够自动调整大小的整形数组。
#include <string>#ifndef CARRAY_H#define CARRAY_Hclass CArray { int size = 0; int * ptr;public: CArray(int s = 0); CArray(const CArray &arr); ~CArray(); void push_back(int value); /* 重载等号操作符, 注意,参数和返回值都是引用类型 */ CArray & operator=(const CArray &arr); int length() { return this->size; } int & operator[](int index) { return ptr[index]; }};#endif // !CARRAY_HCArray::CArray(const CArray &arr) { if (!arr.ptr) { this->ptr == NULL; this->size = 0; return; } ptr = new int[arr.size]; memcpy(ptr, arr.ptr, arr.size * sizeof(int)); this->size = arr.size;}CArray::CArray(int s) :size(s) { if (s == 0) ptr == NULL; else ptr = new int[s];}CArray::~CArray() { if (this->ptr)delete[]ptr;}void CArray::push_back(int value) { if (ptr) { int* tmpPtr = new int[this->size + 1]; memcpy(tmpPtr, ptr, this->size * sizeof(int)); delete[]ptr; ptr = tmpPtr; } else { ptr = new int[1]; } ptr[size++] = value;}CArray & CArray::operator=(const CArray & arr) { if (ptr == arr.ptr) return *this; if (arr.ptr == NULL) { if (this->ptr)delete[] this->ptr; this->size = 0; this->ptr = NULL; return *this;//利用复制构造函数拷贝 } if (this->size < arr.size) { if (this->ptr) delete[] ptr; ptr = new int[arr.size]; } memcpy(ptr, arr.ptr, sizeof(int) * arr.size); size = arr.size; return *this;//利用复制构造函数拷贝}
main函数
#include <iostream>#include "CArray.h"using namespace std;int main(int argc, char* args[]) { CArray a; for (int i = 0; i < 5; ++i) { a.push_back(i); } CArray a2, a3; a2 = a; for (int i = 0; i < a.length(); ++i) { cout << a2[i] << " "; } a2 = a3; for (int i = 0; i < a2.length(); ++i) { cout << a2[i] << " "; } cout << endl; a[3] = 100; CArray a4(a); for (int i = 0; i < a4.length(); ++i) { cout << a4[i] << " "; } system("pause"); return 0;}
类型转换构造函数
目的:实现类型的自动转换
特点:只有一个参数,不是复制构造函数
#include <iostream>using namespace std;class Complex {public: double real, imag; Complex(int i) { real = i; imag = 0; } Complex(double r, double i) { real = r; imag = i; }};int main(int argc, char* args[]) { Complex c(7, 8); Complex c2 = 12; //不是赋值 c = 9; //9被自动转换成一个临时的Complex对象 cout << "c: " << c.real << "," << c.imag << endl; cout << "c2: " << c2.real << "," << c2.imag << endl; system("pause"); return 0;}
执行结果
c: 9,0c2: 12,0
友元
目的是使得一个类能够访问另一个类的私有成员。分为友元函数和友元类。
1、友元类
A是B的友元类, A就可以访问B的私有成员。
#include <iostream>using namespace std;class Car {private: int price;friend class Driver;};class Driver {public: Car car; void modifyCar() { car.price += 1000; }};
2、友元函数
如果类B中的函数fun需要访问类A的私有属性,可以将fun在A中定义为friend的。
#include <iostream>using namespace std;class Car;class Driver {public: void modifyCar(Car* pCar);};class Car {private: int price; friend void Driver::modifyCar(Car* pCar);};void Driver::modifyCar(Car* pCar) {//该函数应该在类Car的文件中 pCar->price += 1000;}
常量对象、常量成员函数、常量引用
方式:增加const关键字
目的:使得对象的字段不可修改。
1、常量对象
如果不希望某个对象的值被改变,在定义该对象的时候可以在前面加const关键字。
class Car {public: int price = 9;};int main(int argc, char* args[]) { const Car car; car.price = 8;//error system("pause"); return 0;}
2、常量成员函数
在类的成员函数说明后面可以加const。
特点:不可以修改其所作用的对象。因此,在常量成员函数中不能修改成员变量的值。(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)
class Sample {public: int value; void getValue() const; void func();};void Sample::getValue()const { value = 0;//wrong, 修改对象的值 func();//wrong, 调用了非常量成员函数}
3、常量成员函数属于重载。
4、常引用
引用前面可以加const,成为常引用。不能通过常引用修改其引用的变量。
const int & r = n;r = 5;//errorn = 4; //ok
当函数的参数是一个对象的时候,推荐使得该参数成为常引用。
操作符重载
目的是让程序更加简洁。使用到了operator关键字。需要注意的是,重载操作符的函数的参数和返回值最好使用引用类型。
#include <iostream>using namespace std;class Opera { int a = 0;public: Opera(int a = 0) { this->a = a; } void print(); Opera & Opera::operator+(const Opera & v);};Opera & Opera::operator+(const Opera & v) { Opera *op = new Opera(this->a + v.a); return *op;}void Opera::print() { cout << this->a << endl;}int main(int argc, char* args[]) { Opera opera(3); Opera opera2(4); Opera opera3 = opera + opera2; opera3.print(); system("pause"); return 0;}
泛型使用
函数泛型
template <class T> //先定义一个泛型的类int getArrayLen(T& array){//使用该泛型 return (sizeof(array) / sizeof(array[0]));}
类泛型
#include <iostream>#include <string>using namespace std;template <class T1, class T2>class Pair {public: T1 key; T2 value; Pair(T1 k, T2 v) :key(k), value(v) {} bool operator<(const Pair<T1, T2> & p)const;};template<class T1, class T2>bool Pair<T1, T2>::operator<(const Pair<T1, T2> & p)const { return key < p.key;}int main(int argc, char* args[]) { Pair<string, int>student("Tom", 19); cout << student.key << " " << student.value << endl; system("pause"); return 0;}
基类类模板1
template <class T1, class T2>class A { T1 v1; T2 v2;};template <class T1, class T2>class B :public A<T2, T1> { T1 v3; T2 v4;};template <class T>class C :public B<T, T> { T v5;};
继承
和java相同。
class Bug {private: int nLegs; int nColor;public: int nType; Bug(int legs, int color) :nLegs(legs), nColor(color){} void PrintBug() {};};class FlyBug :public Bug { int nWings;public: FlyBug(int legs, int color, int wings);};FlyBug::FlyBug(int legs, int color, int wings) :Bug(legs, color),sk1(5), sk2(color) { nWings = wings;}
虚函数和多态
1、问题引入:如下程序并不能实现多态的意图(如果是Java的话这个就可以)
#include <iostream>using namespace std;class Bug {public: void eat() { cout << "base bug!" << endl; };};class FlyBug :public Bug {public: void eat() { cout << "fly bug!" << endl; }};int main(int argc, char* args[]) { FlyBug flyBug; Bug & bug = flyBug; bug.eat(); system("pause"); return 0;}
执行结果为:base bug!
需要修改为:在eat函数前面增加virtual关键字。程序编程如下所示:
#include <iostream>using namespace std;class Bug {public: virtual void eat() { cout << "base bug!" << endl; };};class FlyBug :public Bug {public: void eat() { cout << "fly bug!" << endl; }};int main(int argc, char* args[]) { FlyBug flyBug; Bug & bug = flyBug; bug.eat(); system("pause"); return 0;}
执行结果为:fly bug!
这样子就符合态的意图了。在基类中的eat方法是虚函数,其子类中的eat函数也是,如果没有增加virtual关键字,编译器会自动加上。
虚析构函数
问题引入:通过基类的指针删除派生类对象的时候,只调用基类的析构函数。
应该做到:删除一个派生类的对象的时候,先调用派生类的析构函数,再调用基类的析构函数。
解决方法:把基类的析构函数申明为virtual。派生类的析构函数可以不用申明为virtual。
推荐:
类如果定义了虚函数,则最好将析构函数也定义成虚函数。
抽象类和纯虚函数
纯虚函数的形式:virtual returnType functionName() = 0;
也就是只有函数的申明没有函数体,就像java里面的抽象函数和抽象类。
自定义比较器(函数对象)
#include <iostream>#include <string>#include <set>using namespace std;class StringSort {public: //自定义比较器 bool operator()(const string & str1, const string & str2) { return str1 > str2; }};int main(int argc, char* args[]) { set<string,StringSort> s;//使用自定义比较器 s.insert("a"); s.insert("d"); s.insert("c"); //顺向迭代器 for (set<string>::iterator i = s.begin(); i != s.end(); ++i) { cout << *i << endl; } //反向迭代器 for (set<string>::reverse_iterator i = s.rbegin(); i != s.rend(); ++i) { cout << *i << endl; } system("pause"); return 0;}
template <class T, class Pred>T MyMax(T first, T last, Pred myless) { T tmpMax = first; for (; first != last; ++first) { if (myless(*tmpMax, *first)) { tmpMax = first; } } return tmpMax;}class MyLess {public: bool operator()(int a1, int a2) { if ((a1 % 10) < (a2 % 10)) { return true; } else { return false; } }};bool MyCompare(int a1, int a2) {//作为函数的参数 if ((a1 % 10) < (a2 % 10)) { return true; } else { return false; }}int main(int argc, char* args[]) { int a[] = {35, 7, 13, 19, 12}; cout << *MyMax(a, a + 5, MyLess()) << endl; cout << *MyMax(a, a + 5, MyCompare) << endl; system("pause"); return 0;}
- c
- c
- c
- c
- C
- c
- c
- c
- C+
- c
- C
- c
- c
- c
- C
- C
- c
- C
- Java数据库之修改记录
- Codeforces 431 D. Random Task 数位dp单调性
- static关键字
- C# 单例模式扩展
- webstorm启用emmet出现的问题
- C++
- Java习惯用法总结
- python绘图
- Android崩溃异常捕获方法
- 习题 4.9 给一个不多于5位的正整数,要求:1. 求出它是几位数;2. 分别输出每一位数字;3. 按逆序输出各位数字,例如原数为321,应输出123。
- 初级shell脚本编写示例
- 用Unity实现《随机生成 Tile Based 地图之——洞穴》中的算法
- SimpleDateFormat 的线程安全问题与解决方案
- Qt中的三种基类