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;}
原创粉丝点击