给移动开发者的C++快速入门

本文深入讲解C++的基本数据类型、变量、指针、引用、类的定义与使用、继承、多态等核心概念,以及函数模板、异常处理、输入输出等实用功能。

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

变量

基本数据类型

类型说明
bool布尔型
char字符
int整形
float浮点型
double双精度浮点
void无类型
wchar_t宽字符型,定义:typedef short int wchar_t;
修饰符说明
signed有符号
unsigned无符号
short短型,size缩一半
long长型,size扩一倍
直接上代码:
void testVariant()
{
    int p1 = 1;
    long p2 = 2L;
    float p3 = 3.0;
    double p4 = 4.0;
    char p5 = 'a';
    bool p6 = false;
    short p7 = 100;

    printf("value =  %d, sizeof p1 = %d\n", p1, sizeof(p1));  //value =  1, sizeof p1 = 4
    printf("value =  %ld, sizeof p2 = %d\n", p2, sizeof(p2)); //value =  2, sizeof p2 = 4
    printf("value =  %f, sizeof p3 = %d\n", p3, sizeof(p3));  //value =  3.000000, sizeof p3 = 4
    printf("value =  %lf, sizeof p4 = %d\n", p4, sizeof(p4)); //value =  4.000000, sizeof p4 = 8
    printf("value =  %c, sizeof p5 = %d\n", p5, sizeof(p5));  //value =  a, sizeof p5 = 1
    printf("value =  %b, sizeof p6 = %d\n", p6, sizeof(p6));  //value =  b, sizeof p6 = 0
    printf("value =  %d, sizeof p7 = %d\n", p7, sizeof(p7));  //value =  100, sizeof p7 = 2
}

指针与引用

指针部分与C相同,C++相比C多了两个概念:对象指针和引用,对象指针这部分内容在类的定义和使用中会进行介绍,本节介绍下引用。

引用也是一个地址,记住它的三个特点:

  1. 与指针一样,需要同类型才可以赋值;
  2. 除非做函数的返回值或形参,其余定义引用类型的同时就要初始化;
  3. 引用类型并不是建立一个新的对象,因此不会调用构造函数

引用的使用场景:

  1. 作为函数的形参或返回值,减少不必要的对象的创建,不用传指针也可以操作对象本身;

示例:

Student stu;
Student &stu_q = stu;   //没有创建新的对象
Student stu2 = stu;   //看似赋值,实际上创建了一个新的对象
Student *stu_p = &stu;  //普通的一级指针
stu_q.study();
stu_p->study();
// stu、stu_q、stu_p是同一个对象,而stu2是新的对象
printf("stu = %#x\nstu_q = %#x\nstu_p = %#x\nstu2 = %#x\n",&stu,&stu_q,stu_p,&stu2);

static和const的作用

  • static:
    C/C++中的作用于Java中的非常类似,不同点是static的变量需要在类的外部初始化;
  • const:
    相当于Java中的final,具有两大特性:1)不可修改值;2)定义时初始化(或在构造函数中);
  • static+const
    类的静态常量可以在类内部初始化;
#include <iostream>
using namespace std;


class A{
public:
    //可以直接初始化
    const int a = 0;
    const int b;
    const int c;
    static int d;
    //静态常量可以在类内初始化
    static const int e = 4;
    //在构造方法初始化
    A(int b,int c):b(b),c(c){
        
    }
    
    void print(){
        cout<<a<<"/"<<b<<"/"<<c<<"/"<<d<<"/"<<e<<"/"<<endl;
    }
};
//静态变量再类外初始化
int A::d =3;


int main(int argc, const char * argv[]) {
    A a(1,2);
    a.print();
    return 0;
}

  • const对象
#include <iostream>
using namespace std;

class A{
public:
    const int a;
    int b;
    
    A(int a):a(a){
        b=2;
    }
    
    void print(){
        
    }
    
     void print1() const{
        cout<<a<<"/"<<b<<endl;
    }
};

int main(int argc, const char * argv[]) {
    const A a(1);
    const A a1(2);
    //编译失败,常对象不能被赋值
//    a=a1;
    //此处编译失败,常对象不能调用非常成员函数
//    a.print();
    a.print1();
    return 0;
}

  • const成员函数
  1. 常成员函数的定义和声明都需要包含const
  2. 长城园函数只能调用常成员函数,而不能调用非常成员函数,可以访问但不可以更改非常成员变量
#include <iostream>
using namespace std;

class A{
public:
    const int a;
    int b;
    
    A(int a):a(a){
        b=2;
    }
    
    void print(){
        
    }
    
     void print1() const{
         //此处编译错误,常成员函数不可以改变非常成员变量
//         b=3;
         //此处编译错误,常成员函数不可以调用非常成员变量
//         print();
        cout<<a<<"/"<<b<<endl;
    }
};

int main(int argc, const char * argv[]) {
    const A a(1);
    const A a1(2);
    //编译失败,常对象不能被赋值
//    a=a1;
    //此处编译失败,常对象不能调用非常成员函数
//    a.print();
    a.print1();
    return 0;
}

类的定义和使用

1. public\protected\private访问修饰符
修饰符含义
private表示私有,他所修饰的成员,只能在类的内部访问,外界不能访问
protected除了类内部可以访问,他的子类也可以访问
public内部外部都可以访问
2. 类的定义

第一种定义形式:

class Student{
public:
    char name[100];
    int socre;
    int print(){
        cout<<"/"<<name<<"/"<<socre<<endl;
        return 0;
    }
};   //注意一定要以“;”结尾

第二种形式:

class Student{
public:
    char name[100];
    int socre;
    int print();
};

//1. 成员函数仅仅在类内声明函数原型,在类外定义函数体
//2. 在类外定义函数体的需要类名加上::域限定符
int Sts::print(){
    cout<<"/"<<name<<"/"<<socre<<endl;
    return 0;
}

3. 类的使用
  • 普通创建:
    Student st;   //定义即可使用,不用初始化
    Student *p_st = &st;
    st.socre=100;
    strcpy(st.name, "wang");
    st.print();
    p_st->print();
  • 使用new创建:
int *num= new int;   //new只能创建指针变量
delete a;        //new出来的变量必须调用delete释放内容

int* arr=new int[10];
delete []arr;

Student *p_st = new Student();
delete p_st;
4. 类的构造函数、析构函数、拷贝构造函数(浅拷贝与深拷贝)

这两个概念是成对的,构造=创建+初始化析构=销毁+释放资源拷贝构造=创建+内容复制理解这个概念是关键。

  • 如果用户不定义析构函数,则系统会自动生成一个,如果用户定义,则会在对象销毁时自动调用;
  • 构造函数可以重载,但是析构函数不可以重载,但他可以是虚函数,一个类只能有一个析构函数;
  • 与类同名,且形参是本类对象的引用类型函数,叫做拷贝构造函数,与构造函数一样,如果我们不主动定义,那么系统会自动生成一个(浅拷贝),进行俩个对象成员之间的赋值,用来初始化一个对象

构造函数示例:

#include <iostream>
#include <cstring>
using namespace std;

class Student {
public:
    char name[100];
    int socre;
    // 定义构造函数,实现在外面
    Student (char *str,int sor);
    // 定义成员函数,实现在外面
    void print();
};


Student::Student(char *str,int sor){
    strcpy(name, str);
    socre=sor;
    cout<<"构造函数"<<endl;
}

void Student::print(){
    cout<<a<<"/"<<name<<"/"<<socre<<endl;
}

int main(int argc, const char * argv[]) {
    Student stu(100,"heihei",200);
    stu.print();
    return 0;
}

析构函数示例:

#include <iostream>
#include <cstring>

using namespace std;

class Status{
public:
    int a ;
    char name[100];
    int sorce;
    
    Status(int a ,char *str,int sor);
    ~Status();
};

Status::Status(int a,char *str,int sor){
    this->a=a;
    strcpy(name, str);
    sorce=sor;
    
    cout<<this->a<<name<<sorce<<endl;
}

Status::~Status(){
    cout<<"析构函数"<<endl;
}
int main(int argc, const char * argv[]) {
   
    Status sta(1,"aaa",200);
    Status stw(10,"aaaq",2001);
    
    return 0;
}

输出:
1aaa200
10aaaq2001
析构函数
析构函数

拷贝构造函数示例:

#include <iostream>
#define AA 3.999
using namespace std;

class Status{
public:
    int a ;
    char *str;
    
    Status(int a,char* b);
    Status(Status &A);
    ~Status();
};

Status::Status(int a,char* b){
    this->a=a;
    this->b=new char[strlen(b)+1];
    strcpy(this->b,b);
}

// 一般定义拷贝函数的目前是为了做深拷贝,因为系统默认的拷贝函数是浅拷贝
Status::Status(Status &A){
    this->a=A.a;
    this->b=new char[strlen(b)+1];
    strcpy(this->b,b);
}

Status::~Status(){
	delete []b;
}

int main(int argc, const char * argv[]) {
    Status st(1,2);
    Status sts(st);
    return 0;
}
5. friend友元类、函数

要点:

  • friend函数用于实现外部函数访问本类的私有属性或方法;
  • friend类用于实现外部类访问本类的私有属性和方法;
  • 友元函数
#include <iostream>
using namespace std;

class Status{
private:
    int a;
    int b;
    
public:
    Status(int a,int b){
        this->a=a;
        this->b=b;
    };
    
    // friend函数需要在本类进行定义
    friend void print(Status st);
};

void print(Status st){
    cout<<st.a<<"/"<<st.b<<endl;
}

int main(int argc, const char * argv[]) {
    Status st(1,2);
    print(st);
    return 0;
}

  • 有元类
#include <iostream>
using namespace std;


class  Status{
private:
    int a;
    int b;
    
public:
    Status(int a,int b){
        this->a=a;
        this->b=b;
    };
    
    friend class A;
};

class A{
public:
    void print(Status &st){
        cout<<st.a<<"/"<<st.b<<endl;
    }
};

int main(int argc, const char * argv[]) {
    
    Status st(1,2);
    A a;
    a.print(st);
    
    return 0;
}

6. 类的继承(派生)

与Java差不多,直接看demo:

#include <iostream>
using namespace std;

class A{
public:
    int a;
    
    A(){
        cout<<"父类的无参构造函数"<<endl;
    }
    
    A(int a){
        this->a=a;
        cout<<"父类的有参构造函数"<<endl;
    }

    ~A(){
        cout<<"父类的析构函数"<<endl;
    }
    
    void setA(int a){
        this->a=a;
    }
    
    void showA(){
        cout<<a<<endl;
    }
};

// 三种继承方式:public、protected、private,决定子类继承来的属性和方法的访问权限
class B:public A{
public:
    int b;
	//这里B的构造函数虽然没有显式调用A的构造函数,但是会先执行A的构造函数
    B(){
        cout<<"子类的无参构造"<<endl;
    }
    //指定父类带参构造和参数
    B(int a):A(a){
        cout<<"子类的有参构造函数"<<endl;
    }

	// 会先调用子类B的析构函数,在调用父类A的析构函数
    ~B(){
        cout<<"子类的析构函数"<<endl;
    }
    
    void setB(int b){
        this->b=b;
    }
   
    void showB(){
        cout<<b<<endl;
    }
};

int main(int argc, const char * argv[]) {
    B b;
    b.setA(1);
    b.setB(2);
    b.showA();
    b.showB();
    return 0;
}

7. 类的多态(virtual虚基类、虚函数、抽象类)

virtual在功能上可以类比java的abstract关键词,

A
B
C
D

如上图的继承关系,无法通过编译(多次拷贝有歧义),此时的解决办法就是在B、C的定义上加上virtual关键词。

上面是虚基类的应用,除此之外,虚函数可以实现多态:

#include <iostream>
using namespace std;


class A{
public:
	// 在父类中定义虚函数或虚析构函数
    virtual void print(){
        cout<<"A"<<endl;
    };

	// 1. 纯虚函数没有方法体,由子类实现
	// 2. 后面加一个=0,表示没有函数体
	// 3. 含有纯虚函数的类就是抽象类,一个抽象类至少有一个纯虚函数
	virtual void test()=0;
};

class B : public A{
public:
    void print(){
        cout <<"B"<<endl;
    }

	void test(){
		cout <<"test"<<endl;
	}
};


int main(int argc, const char * argv[]) {
    A a;
    a.print();
    B b;
    b.print();
    
    A *p;
    p=&b;
    p->print();
    
    A &pp=b;
    pp.print();
    
    return 0;
}

虚函数注意点:

  • 虚函数不能是静态成员函数,或友元函数,因为他们不属于某个对象
  • 内联函数不能运行中动态指定其位置,即使虚函数在类内定义,编译时,仍将看做非内联
  • 构造函数不能是虚函数,析构函数可以是虚函数,而且通常声明为虚函数(这个还是好理解的,不同的子类占用的资源类型和数量不同,利用虚析构函数可以实现不同的资源释放逻辑)

函数

函数特性

1. 导包
导标准库
#include<iostream>
导入三方包
#include "mylib.h"

再来回顾下C语言的导包:

导标准库:
eg. #include <stdlib.h>
导第三方包:
eg. #include “jni.h”
eg. #include “test.c”

c与c++头文件的区别点:

  • c++导系统包时<>内没有.h
  • c++中可以用static和inline解决函数链接错误,static告诉编译器对应的函数仅在本c++文件中使用不对外提供(类似Java中的private),inline告诉编译器每次外部调用本函数时都拷贝完整函数代码到调用处
  • c++的.h采用#pragma once来解决循环引用问题

标准.h头文件格式:


#ifndef <自定义标识>
#define <自定义标识>
#ifdef __cplusplus
extern "C" {
#endif

// 正常的申明区

#ifdef __cplusplus
}
#endif
#endif

资料:#ifdef __cplusplus

2. 命名空间

使用了命名空间,可以省去重复的代码,也可以解决命名空间重复的冲突

#include <iostream>
using namespace std;
 
// main() 是程序开始执行的入口
int main()
{
   cout << "Hello World"; // 输出 Hello World
   return 0;
}

上述代码不使用命名空间:

#include<iostream>
int main()
{
    std::cout<<"Nice to meet you!"<<std::endl;
    return 0;
}

也可以指定使用哪些函数的命名空间,不过不常用:

#include<iostream>
using std::cout;
using std::endl;
int main()
{
    cout<<"Nice to meet you!"<<endl;
    return 0;
}
3. 形参默认值

c++支持函数形参带默认值:

int add(int x=1, int y=2)
{
    return x + y;
}
int main()
{
    int a,b,c,d;
    a = add();
    b = add(5);
    c = add(10, 12);
    // d = add(., 23);  //非常遗憾不支持省略左边的参数
    printf("a = %d,\nb = %d,\nc = %d\n", a, b, c);
    return 0;
}

输出:
a = 3,
b = 7,
c = 22

4. 函数模版template

格式:template<class T1,class T2…>
作用于java的泛型有点类似,上述代码定义了两个类型参数T1和T2,就可以用这两个类型参数作为形参去定义函数,从而实现函数的重载

示例:

#include <iostream>

using namespace std;

template<class T1,class T2>

T1 add(T1 x,T2 y){
    cout<<sizeof(T1)<<"/"<<sizeof(T2)<<endl;
    return x+y;
}

int main(int argc, const char * argv[]) {
    cout<<add(1,2)<<endl;
    cout<<add(0.22, 0.33)<<endl;
    cout<<add('A',2)<<endl;
    return 0;
}

输出:
4/4
3
8/8
0.55
1/4
C

5. 内联函数inline

使用内敛函数编译的时候,把函数代码插入到函数调用的地方, 就像普通的程序执行代码一样。
内敛函数使用场景:函数本身不长,但是又是频繁调用

kotlin也借鉴了这个特性,甚至名字都一样也是inline

示例:

#include <iostream>

using namespace std;
// 1. 内联函数的调用要出现在调用之前,才可以让编译器了解上下文进行代码替换

inline int max(int x,int y){
    return x>y?x:y;
}
int main(int argc, const char * argv[]) {
    cout<<max(12, 2)<<endl;
    cout<<max(2, 13)<<endl;
    return 0;
}

6. 异常处理

C++的异常处理和java的差不多都是用到了try,catch,throw三个关键字。
示例:


#include <iostream>
using namespace std;


int main(int argc, const char * argv[]) {
    int a =0;
    int b=1;
    cout<<a<<"/"<<b<<endl;;
    try {
        if (a==0) {
            throw "a为0异常";
        }
    } catch (const char *str) {
        cout<<str<<endl;
    }
    return 0;
}

C++中标准异常类:
C++标准异常类
示例:

异常定义场景
bad_alloc当new一个对象,内部不足,会抛出bad_alloc异常
out_of_range使用string类下标越界时
#include <iostream>
#include <new>
#include <stdexcept>
using namespace std;

int main(int argc, const char * argv[]) {
    string *s;
    
    try {
       s = new string("123456");
        cout<<s->substr(7,3);
    } catch (bad_alloc &t) {
       cout<<"异常:"<<t.what()<<endl;
    }catch(out_of_range &t){
        cout<<"异常:"<<t.what()<<endl;
    }
    return 0;
}

输出:
异常:basic_string

输入输出函数

1. 屏幕输出
using namespace std

// 使用<<符号,有点类似于bat脚本语言中重定向符`<`和`>`,只不过这里是两个
cout << "hello c++";

// 输出hello cppfred,无空格无换行
cout << "hello cpp" << "fred";

// 使用endl进行换行
cout <<"hello"<<endl<<"cpp";
2. 键盘输入
// 第一步:定义一个变量接收输入的数据
int a,b; 
cout<<"请输入一个数字:"<<endl

// 第二步:使用cin进行赋值
cin>>a;
// cin>>a>>b;  //也可以一次赋值给多个变量

// 第三步:打印a的值
cout<<"a=%d" a<<endl

文件读写

C++定义了三个类分别负责,读,写,读写操作:

类型作用
ofstream (out)表示输出文件流,用于创建文件并向文件写入信息。
ifstream (in)表示输入文件流,用于从文件读取信息。
fstream (file)表示文件流,且同时具有 ofstream 和 ifstream 两种功能,这意味着它可以创建文件,向文件写入信息,从文件读取信息。

打开文件:void open(const char *filename, ios::openmode mode);

  • 第一个参数表示打开文件的路径
  • 第二参数表示打开的模式
    参数|作用
    —|—
    ios::in|为输入(读)而打开文件
    ios::out|为输出(写)而打开文件
    ios::ate|初始位置:文件尾
    ios::app|所有输出附加在文件末尾
    ios::trunc|如果文件已存在则先删除该文件
    ios::binary|二进制方式
    除此之外还可以通过|符号将多个参数进行使用:
ofstream out;  
out.open("dotcpp.txt", ios::out|ios::binary)  //以二进制模式打开,进行写数据

读写测试:

void testRead(){
	char data[100];
    ifstream in;
    in.open("/Users/renxiaohui/Desktop/test.txt");
    in>>data;
    cout<<data<<endl;
    in.close();
}

void testWrite(){
	const char *name="测试测试测试";
    ofstream out;
    out.open("/Users/renxiaohui/Desktop/test1.txt");
    out<<name;
    out.close();
}

字符串自操作

// 字符串长度
const char *c_data="abc"
int len_data = strlen(c_data);
// 字符串拷贝
char cc_data[len_data];
strcpy(cc_data, c_data);

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值