C++学习笔记

这篇博客详细介绍了C++编程的基础知识,包括面向对象、声明与定义、头文件的使用、对象初始化、内存管理等方面。讲解了类、对象、访问限制、内联函数、const修饰符以及C++的内存模型。还深入探讨了多态性、拷贝构造、静态成员和运算符重载等关键概念。此外,提到了模板和异常处理在C++中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1.面向对象

2. First programme — 声明、定义和实体

(1) “::” —解析符 

(2) 声明

(3) 定义

(4)实体

3. 头文件

(1).h 和 .cpp

(2)#include

4. 字段(类的成员变量),函数参数和本地变量

5. 对象初始化

6. new & delete

7. 访问限制

8. 初始化列表

9. 对象组合

10. 继承

11. 内联函数 inline

12. const

13. C++的内存模型

14.引用

15.向上造型

16.多态性 & virtual

17.拷贝构造

18.静态 static

19.运算符重载

20.模板

21.异常

22.流


1.面向对象

(1)对象的意义相当于C语言中的变量,它组成类似于属性+服务/数据+对外接口。

        对象通过接口接收信息,由接口定义对象属于什么类型。

        接口的作用:通信交流信息;保护数据。

(2)面向对象:按照存在,是指程序描述有什么内容,内容的关系是什么。

                           问题空间 —映射(map)— 方法空间

         面向过程:按照时间顺序,是指事情发生的流程是什么。

 (3) 类和对象 :类是对象的定义,对象是类的一种实例。

(4) 对象的五个原则

程序的所有都是是对象;

程序是通过传递信息告诉彼此做什么(而不是怎么做)的对象的集合;

每个对象有其他对象组成的自己的内存;

每个对象有自己的类型;

一个类型的所有对象可以接收相同的消息。

2. First programme — 声明、定义和实体

(1) “::” —解析符 

 <Class Name> :: <function name> 类中的一个函数(非全局函数)

 

  :: <function name>   

(2) 声明

函数原型:类型标识符 被调用函数名(含类型说明的形参表)


(3) 定义

class 类名称 {

public:

        公有成员(外部接口);

private:

        私有成员;

protected:

        保护型成员;

};

(4)实体

可以理解为一个对象实例,就是用这个类型定义的一个变量。

3. 头文件

(1).h 和 .cpp

.h 存放类的声明,.cpp存放函数的定义。

(2)#include

tips:每一个类应该放在一个头文件里(每一个头文件只放一个类的声明);

         对应的源代码文件用相同的前缀;

         头文件要用标准头文件围绕起来 #ifndef #define #endif;

         

4. 字段(类的成员变量),函数参数和本地变量

成员变量存在类的对象里(类只是声明存在该成员变量)。函数属于类而不是对象。

函数参数和本地变量性质一致,存放在堆栈。

类的函数能够区分同类不同对象的函数内的成员变量。

5. 对象初始化

对象初始化可以分为默认初始化、直接初始化、拷贝初始化以及值初始化。

(1)默认初始化
如果定义变量时没有指定初值,则变量被默认初始化,此时变量被赋予了“默认值”。

int i;
A a;

(2)直接初始化

如果不使用等号,则执行的是直接初始化。

int a(0);
string str1("hello");
string str2(10, 'c');//这种情况拷贝初始化不能完成
A a(pa);

(3)拷贝初始化

如果使用一个等号初始化一个变量,实际上执行的是拷贝初始化。编译器会把等号右侧的初始值拷贝到新创建的对象中去。

int a = 0;
int a = {0};
string str1 = "hello";
A pa; A a = pa;

(4)值初始化

值初始化仅限于容器类。

vector<int> v1(10);//v1有10个元素,每个的值都是0
vector<int> v2{10};//v2有1个元素,该元素的值是10
vector<int> v3(10, 1);//v3有10个元素,每个的值都是1
vector<int> v4{10, 1);//v4有2个元素,值分别是10和1

6. new & delete

new & delete 相当于C语言当中的malloc & free,作用是动态存储。

new是在运行中向内存申请空间,可以使用指针访问这块内存。delete 析构并释放申请的空间。

如果未析构空间,即申请数组空间后,delete未加[],会造成内存泄漏(内存泄漏是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果)。

new 和 malloc 的区别

1.malloc与free是c++/c语言的标准函数,new/delete是C++的运算符;

2.new和delete在对象创建的时候自动执行构造函数,对象消亡之前会自动执行析构函数;

3.new返回指定类型的指针,并且可以自动计算出所需要的大小。malloc必须用户指定大小,并且默然返回类型为void*,必须强行转换为实际类型的指针。

4.new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。

5.使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。

int * psome = new int [10];

delete [] psome;


//void *malloc(int size[num]); 
//void free(void *size);

7. 访问限制

public & private & protected

public :公开; private :只有类的成员函数可以访问(同一个类之间可以互相访问私有变量);

protected:只有类自己的成员函数或子类可以访问 。

friend:授权访问私有变量。

8. 初始化列表

class Student {
private :
    int name;
public :
    Student(string s) {};
    ~Student {};
    void f();
};

Student :: Student(string s) : name(s) {}

// Student :: Student(string s) {

//name = s;

//}

9. 对象组合

用已有的对象创造新的对象(实体);对象可以用来构建对象;

组合方法:fully(成员变量是对象本身) & by reference (成员变量是指针);

构造函数内的对象由对象本身进行初始化。

10. 继承

用已有的类进行改造构造新的类。基类可以产生多个派生类,派生类可以有多个基类;

派生类可以访问基类中所有的非私有成员。

(1) 三种继承方式

公有继承方式:会把基类的公有成员(变量和函数)继承到子类公有成员,保护成员 变成基类的保护成员,但是私有成员子类也一样不可以访问。

保护继承方式:会把基类的公有成员或者保护成员(变量和函数)变成子类的保护成员,但是私有成员子类也一样不可以访问。

私有继承方式:结果上和保护继承方式一致。

(2) 多继承

class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…
{
<派生类类体>
};

11. 内联函数 inline

 程序在编译器编译的时候,编译器将程序中出现的内联函数的调用表达式用内联函数的函数体进行替换,而对于其他的函数,都是在运行时候才被替代。这其实就是个空间代价换时间的i节省。

  • 1.在内联函数内不允许使用循环语句和开关语句;
  • 2.内联函数的定义必须出现在内联函数第一次调用之前;
  • 3.类结构中所在的类说明内部定义的函数是内联函数;
  • 4.有些函数即使声明为内联的也不一定会被编译器内联。

12. const

const 某个值保持不变, 用来修饰内置类型变量,自定义对象,成员函数,返回值,函数参数。

const 在C和C++中的含义

(1)C中的const:
作用:被修饰的内容不可更改。
使用场合:修饰变量,函数参数,返回值等。
特点: 运行时const,因此不能取代#define用于成为数组长度等需要编译时常量的情况。同时因为是运行时const,可以只定义而不初始化,而在运行时初始化。如 const int iConst;。 另外,在c中,const变量默认是外部链接,因此在不同的编译单元中如果有同名const变量,会引发命名冲突,编译时报错。


(2)C++中的const:

a、非类成员const:

①const变量默认是内部连接的,因此在不同的编译单元中可以有同名的const 变量定义。

②编译时常量,因此可以像#define一样使用,而且因为上面一点,可以在头文件中定义const变量,包含的不同的cpp文件(编译单元)中使用而不引起命名冲突。

③编译器默认不为const变量分配内存,除非:1. 使用 extern 申明, 2:程序中有引用const 变量的地址。

④c++中临时对象/内置变量默认具有const属性。

b、类中的const:

①与c语言中的const一样,只是运行时常量,不能作为数组维数使用,即不能取代#define。在类中使用下面两种方式取代#define:

1:static const... 

2 : enum{....}//enum 不占存储空间。

②类中的const 变量占用存储空间。

③类中的const成员变量需要在构造函数初始化列表中初始化。

④const 对象:在该对象生命周期内,必须保证没有任何成员变量被改变。const对象只能调用const成员函数。

⑤const成员函数: void fun() const ... 不仅能被const对象调用,也能被非const对象调用,因此,如果确认一个任何成员函数不改

变任何成员变量,应该习惯性将该函数定义成const类型。

⑥如果一个对象被定义成const,那么该const对象“可能”会被放入到ROM当中,这在嵌入式开发当中有时非常重要。
————————————————
版权声明:本节为CSDN博主「Xiao__Tian__」的原创文章
原文链接:https://blog.csdn.net/xiao__tian__/article/details/51814617

const int* p ; // 定义一个指向不可修改的变量的地址指针

const int* const p ; // 定义一个不可修改地址的变量指针

calss A 
{
public :
void f() {};
void f() const {}; // 定义一个不可修改变量的函数,相当于f(const A* this)

};

13. C++的内存模型

C++的内存模型:

存放对象的方式(堆,堆栈,全局数据区);

访问对象的方式(变量,指针,引用);

java的内存模型:

存放对象的方式(堆);

访问对象的方式(指针);

C/C++的指针可以做计算,java的指针无法做计算;

C/C++的对象的地址可以是绝对值直接交给指针访问;

14.引用

引用声明的如果是类的成员或本地变量时,不能在声明时赋值;

函数返回类型为引用时,不能返回成员变量或者本地变量。

int c[] = {0,1,2}; //c:对象

int* p = &c; // p:指向对象c地址的指针

int& r = c; // r:对象c的引用(又称为别名),引用的实质是指针(const的指针)

int *& y;


void f(int& c); //引用作为参数传给函数,比一般参数更安全

f(r);


int& f(int i){

int& s = c[i];

return s;

} 

int main(){

f(2)=20; //当函数返回一个引用,即返回一个指向返回值的隐式指针,函数可以放在赋值语句的左边

return 0;
}

引用 vs 指针

  • 不存在空引用。引用必须连接到一块合法的内存。
  • 一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
  • 引用必须在创建时被初始化。指针可以在任何时间被初始化。
  • 引用之间不能互相赋值。
  • 引用常见的使用用途:作为函数的参数、函数的返回值。

15.向上造型

子类对象具有父类对象所具有的绝大部分成员, 除了父类的私有成员,有时候会把子类对象当作父类对象看待。

class manager: pubilc employee

{

  manager();

}

manager pett;

employee *ep = &pett;    //就是upcast

employee &ep = pett;    //也是upcast

造型和类型转换的区别

造型并不会丢失数据,而只是将数据类型看成了另一种类型,如向上造型,将对象D看成对象B,只能访问类B的成员变量和成员函数,但是对象D中包含的关于类D 的东西并没有丢失。而类型转换是存在数据丢失的,如将double类型转换为int类型,那么会丢失一部分数据,降低数据精度,丢失的数据无法找回。

16.多态性 & virtual

编译时多态性(静态多态):通过重载函数实现:先期联编 early binding

运行时多态性(动态多态):通过虚函数实现 :滞后联编 late binding。在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。

虚函数

通过指针或者引用调用函数时,将根据指针指向的对象类型确定调用的函数,而非指针的类型,运行时才能确定调用的函数。

虚函数的使用将导致类对象占用更大的内存空间。对这一点的解释涉及到虚函数调用的原理:编译器给每一个包括虚函数的对象添加了一个隐藏成员:指向虚函数表的指针(vptr)。虚函数表(virtual function table)包含了虚函数的地址,由所有虚函数对象共享。当派生类重新定义虚函数时,则将该函数的地址添加到虚函数表中。无论一个类对象中定义了多少个虚函数,虚函数指针只有一个。相应地,每个对象在内存中的大小要比没有虚函数时大4个字节(32位主机,不包括虚析构函数)。

class XYPos {...}; // x,y point;

class Shape {
public :
    Shape();
    virtual ~Shape();
    virtual void render();
    void move(const XYPos&);
    virtual void resize();
protected :
    XYPos center;
};

class Ellipse : public Shape {
public:
    Ellipse(float maj, float minr);
    virtual void render();
protected:
    float major_axis, minor_axis;
};

class Circle : public Ellipse {
public:
    Circle(float radius) : Ellipse(radius,radius){}
    virtual void render();
};

void render(Shape* p) {
    p->render());//p是多态的,又称为多态对象,使函数的形态为指向的形态
}

void func() {
    Ellipse ell(10,20);
    ell.render();
    Circle circ(40);
    circ.render();
    render(&ell);
    render(&circ);
}

虚基类:

可以使得从多个类(它们继承自一个类)中派生出的对象只继承一个对象。

17.拷贝构造

拷贝构造函数在没有声明时系统会自动生成。

T :: T(const T&) ;

#include <string>

class P {
public:    
    P();
    virtual P();
    P(const string&); // 不希望拷贝构造可私有
    ~P();
};

18.静态 static

static in C: 存储持久存储; 访问性受局限;

C/C++共有用途 :

静态局部变量:在全局/静态区分配内存空间;只执行一次初始化,延长了局部变量的生命周期,在程序结束的时候才释放。

静态全局变量:只能在当前的文件中访问,其它文件不可访问(包括extern)。

静态函数:只能在当前文件中访问,不可在其它文件中调用。

C++特有用途:

静态成员变量

实质是做为该类成员的全局变量,类的所有实体对象共享这个变量;

类的数据成员在类外定义时不加 static;

静态成员变量只有在类外声明时才分配空间,可显式初始化,不显式初始化OS默认初始化为0;

静态成员变量属于类不属于对象,sizeof()的结果不包括静态成员变量大小;

静态常量整型数据成员可在类内初始化,也可在类外初始化。

静态成员函数

静态成员函数中只能调用静态成员变量和静态成员函数;

类的静态成员函数在类外实现时,与数据成员一样不需要加 static。

19.运算符重载

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

Box operator+(const Box&, const Box&);

类型转换

X :: operator T()

20.模板

指C++程序设计设计语言中采用类型作为参数的程序设计,支持通用程序设计。模板是C++支持参数化多态的工具,使用模板可以使用户为类或者函数声明一种一般模式,使得类中的某些数据成员或者成员函数的参数、返回值取得任意类型。

函数模板:

template <class 形参名,class 形参名,......> 
 返回类型 函数名(参数列表)
 
   {
 
      函数体
 
   }

template <class T>

void swap( T& x, T& y ) {
    T temp = x;
    x = y;
    y = temp;
} 

template <class T>
void foo( void ){ /*...*/ }
foo<int>();
foo<float>();

类模板:

template<class  形参名,class 形参名,…>
    class 类名{ ... };


template<class T> class A{
     public: 
          A(int);
          ~A();
          A(const A&);
          A& operator = (const A&);
          T& operator [](int);
     private:
          T* m_elements;
          int m_size;
};

//在类A中声明了两个类型为T的成员变量a和b,一个返回类型为T带两个参数类型为T的函数qzj

template <typename T>
class Parent{
public:
    Parent(T p)
    {
        this->p = p;
    }
    
private:
    T p;
};

//如果子类不是模板类,需要指明父类的具体类型
class ChildOne:public Parent<int>{
    
public:
    ChildOne(int a,int b):Parent(b)
    {
        this->cone = a;
    }
    
private:
    int cone;
};


//如果子类是模板类,可以用子类的泛型来表示父类
template <typename T>
class ChildTwo:public Parent<T>{
    
public:
    ChildTwo(T a, T b):Parent<T>(b)
    {
        this->ctwo = a;
    }
    
private:
    T ctwo;
};

可以定义相同的操作,拥有不同数据类型的成员属性。

通常使用template声明。告诉编译器,碰T到不要报错,表示一种泛型。

  • 如果父类自定义了构造函数,记得子类要使用构造函数列表来初始化
  • 继承的时候,如果子类不是模板类,则必须指明当前的父类的类型,因为要分配内存空间
  • 继承的时候,如果子类是模板类,要么指定父类的类型,要么用子类的泛型来指定父类

本节作者:岁与禾
链接:https://www.jianshu.com/p/70ca94872418
来源:简书
 

21.异常

异常是程序在执行期间产生的问题。C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。异常提供了一种转移程序控制权的方式。

异常语句

C++ 异常处理涉及到三个关键字:try、catch、throw

  • throw: 当问题出现时,程序会抛出一个异常。这是通过使用 throw 关键字来完成的。
  • catch: 在您想要处理问题的地方,通过异常处理程序捕获异常。catch 关键字用于捕获异常。
  • try: try 块中的代码标识将被激活的特定异常。它后面通常跟着一个或多个 catch 块。
    template <class T> class Vector {
        private:
            T* m_elements;
            int m_size;
        public:
            Vector (int size = 0) : m_size(size)...
            ~Vector () {delte[] m_elements;}
            void lwngth(int);
            int length() {return m_size;}
            T& operator[](int);
    };
    
    class VectorIndexError {
        public:
            VectorIndexError(int v) : m_badValue(v) {}
            ~VectorIndexError() {}
            void diagnostic() {
                cerr << "index" << m_badValue << "out of range!";
        }
        private:
            int m_badValue;
    };
    
    template <class T>
    T& Vector<T>::operator[](int index) {
        if (index < 0 || index >= m_size) {
            throw VectorIndexError(index);
        }
        return m_elements[index];
    }
    
    //Case 1 : 
    int func() {
        Vector<int? v(12);
        v[3] = 5;
        int i = v[42];
        return i*5; 
    }
    
    //Case 2:
    void outer() {
        try {
            func(); func2();
    } catch (VectorIndexError& e){
        e.diagnostic();
    }
        cout << "Control is here after exception";
    }
    
    //Case 3:
    void outer2() {
        String err("exception cauught");
        try {
            func();
    } catch (VectorIndexError) {
        cout << err;
        throw;
        }
    }
    
    //Case 4:
    void outer3() {
        try {
            puter2();
    } catch (...) {
        cout << "The exception stops here!"
    }
    }

    22.流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值