c++学习笔记

这篇博客记录了学习C++的过程,重点介绍了C++的基本语法,包括输入输出、默认参数、函数重载、函数模板、模板重载和对象与类等。通过一个Hello World示例开始了C++的学习,并探讨了C++与C语言的区别,特别是C++的面向对象和泛型编程特性。

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

前言

看到本博最近都在学习机器学习,怎么突然冒出一篇C++的笔记,有点突兀……这是因为最近在学怎么获取数据,然后喂给机器学习算法,现在想从原始网络流量包中获取kdd99格式,网上找了下,有个现成的源码是使用C++写的,所以就花了半天时间看了下C++。

也就是说主要目的是为了看懂一个C++原程序,所以和C++相关的知识点是不全的,后续如有时间会再补充更新。

参考书籍《C++Primer.Plus(第6版)》

C++和C语言的主要区别是支持面向对象编程和泛型编程,本笔记不对C语言做记录,而仅记录C++的新特性。

Hello world

先有个直观认识。

运行环境:CentOS 5.4

新建名为hello.cpp的文件,内容如下:

#include <iostream>

int main(int argc, char **argv)#或者int main(void),或者int main()
{
    std::cout << "hello world" << std::endl;

    return 0;
}

编译和运行:

[root@ceshi03 c++]# g++ hello.cpp -o hello
[root@ceshi03 c++]# ./hello 
hello world
[root@ceshi03 c++]# 

不同编译器约定的语法不一样,常见的有:.cc、.cxx、.cpp、.cp以及.C

基本语法

基本语法主要列出和C语言不一样的内容。

输入输出

需要头文件

#include <iostream>

标准输入:std::cin

标准输出:std::cout

标准错误:std::cerr和std::clog

例子:

#include <iostream>

int main()
{
    int a=0, b=0;
    std::cin >> a >> b;
    std::cout << "The num of " << a << " and " << b 
        << " is " << a+b << std::endl;

    return 0;
}
[root@ceshi03 c++]# g++ std.cpp 
[root@ceshi03 c++]# ./a.out 
2 3
The num of 2 and 3 is 5

>>:输入运算符
<<:输出运算符

默认参数

char * left(const char * str, int n = 1);

函数重载(函数多态)

函数重载和函数多态是同一概念,它支持多个相同的函数名定义,但其形参变量类型或个数不一样,最简单的代码如下所示,其还有一些细节上需要注意的地方,比如哪些可以重载,哪些不可以重载。

#include <iostream>
using namespace std;
//交换 int 变量的值
void Swap(int *a, int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}
//交换 float 变量的值
void Swap(float *a, float *b){
    float temp = *a;
    *a = *b;
    *b = temp;
}
//交换 char 变量的值
void Swap(char *a, char *b){
    char temp = *a;
    *a = *b;
    *b = temp;
}
//交换 bool 变量的值
void Swap(bool *a, bool *b){
    char temp = *a;
    *a = *b;
    *b = temp;
}
int main(){
    //交换 int 变量的值
    int n1 = 100, n2 = 200;
    Swap(&n1, &n2);
    cout<<n1<<", "<<n2<<endl;
    //交换 float 变量的值
    float f1 = 12.5, f2 = 56.93;
    Swap(&f1, &f2);
    cout<<f1<<", "<<f2<<endl;
    //交换 char 变量的值
    char c1 = 'A', c2 = 'B';
    Swap(&c1, &c2);
    cout<<c1<<", "<<c2<<endl;
    //交换 bool 变量的值
    bool b1 = false, b2 = true;
    Swap(&b1, &b2);
    cout<<b1<<", "<<b2<<endl;
    return 0;
}

函数模板

在C语言中如果要交换两个int,两个double就要定义两个函数,C++就可以使用函数模板解决这个问题。

定义一个模板:

template <typename AnyType>

关键字template和typename是必须的,typename位置也可使用class,另外必须使用尖括号,类型名AnyType可以任意选择,只要符合C++命名规范即可,一般常用T来命名。

如下代码演示了模板的使用,它通过调用的地方传入不同类型的变量来决定T的类型,而最终生成带什么类型的函数由编译器完成。

#include <iostream>
// function template prototype
template <typename T>  // or class T
void Swap(T &a, T &b);

int main()
{
    using namespace std;
    int i = 10;
    int j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j);  // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ".\n";

    double x = 24.5;
    double y = 81.7;
    cout << "x, y = " << x << ", " << y << ".\n";
    cout << "Using compiler-generated double swapper:\n";
    Swap(x,y);  // generates void Swap(double &, double &)
    cout << "Now x, y = " << x << ", " << y << ".\n";
    // cin.get();
    return 0;
}

// function template definition
template <typename T>  // or class T
void Swap(T &a, T &b)
{
    T temp;   // temp a variable of type T
    temp = a;
    a = b;
    b = temp; 
}

模板重载

原来的模板类型为(T &, T&),新模板的类型为(T , T , int)。从中也可以知道模板参数并非一定是模板参数类型,而是可以是具体的类型。

#include <iostream>
template <typename T>     // original template
void Swap(T &a, T &b);

template <typename T>     // new template
void Swap(T *a, T *b, int n);

void Show(int a[]);
const int Lim = 8;
int main()
{
    using namespace std;
    int i = 10, j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j);              // matches original template
    cout << "Now i, j = " << i << ", " << j << ".\n";

    int d1[Lim] = {0,7,0,4,1,7,7,6};
    int d2[Lim] = {0,7,2,0,1,9,6,9};
    cout << "Original arrays:\n";
    Show(d1); 
    Show(d2);
    Swap(d1,d2,Lim);        // matches new template
    cout << "Swapped arrays:\n";
    Show(d1);
    Show(d2);
    // cin.get();
    return 0;
}

template <typename T>
void Swap(T &a, T &b) 
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

template <typename T>
void Swap(T a[], T b[], int n)
{
    T temp;
    for (int i = 0; i < n; i++)
    {
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

void Show(int a[])
{
    using namespace std;
    cout << a[0] << a[1] << "/";
    cout << a[2] << a[3] << "/";
    for (int i = 4; i < Lim; i++)
        cout << a[i];
    cout << endl;
}

显示具体化(explicit specialization)

如果有多个原型,则编译器在选择原型时,非模板版本优先显示具体化和模板版本,而显示具体化优先模板版本。

#include <iostream>
template <typename T>
void Swap(T &a, T &b);

struct job
{
    char name[40];
    double salary;
    int floor;
};

// explicit specialization 
template <> void Swap<job>(job &j1, job &j2);
void Show(job &j);

int main()
{
    using namespace std;
    cout.precision(2);
    cout.setf(ios::fixed, ios::floatfield);
    int i = 10, j = 20;
    cout << "i, j = " << i << ", " << j << ".\n";
    cout << "Using compiler-generated int swapper:\n";
    Swap(i,j);    // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ".\n";

    job sue = {"Susan Yaffee", 73000.60, 7};
    job sidney = {"Sidney Taffee", 78060.72, 9};
    cout << "Before job swapping:\n";
    Show(sue);
    Show(sidney);
    Swap(sue, sidney); // uses void Swap(job &, job &)
    cout << "After job swapping:\n";
    Show(sue);
    Show(sidney);
    // cin.get();
    return 0;
}

template <typename T>
void Swap(T &a, T &b)    // general version
{
    T temp;
    temp = a;
    a = b;
    b = temp;
}

// swaps just the salary and floor fields of a job structure
template <> void Swap<job>(job &j1, job &j2)  // specialization
{
    double t1;
    int t2;
    t1 = j1.salary;
    j1.salary = j2.salary;
    j2.salary = t1;
    t2 = j1.floor;
    j1.floor = j2.floor;
    j2.floor = t2;
}

void Show(job &j)
{
    using namespace std;
    cout << j.name << ": $" << j.salary
         << " on floor " << j.floor << endl;
}

实例化

之前的例子在调用Swap(i,j)时传入的i,j为int类型,生成一个Swap()的实例,这种实例化称为隐式实例化。C++还允许显示实例化(explicit instantiation),可通过类似的语法:Swap(),其声明所需的种类用<>符号指示类型,并在声明前加上template:

template void Swap<int>(int, int);

对象和类

面向对象编程(OOP)主要特性:

  • 抽象
  • 封装和数据隐藏
  • 多态
  • 继承
  • 代码的可重用性

C++中的类

定义一个类

文件名:stock00.h

#ifndef STOCK00_H_
#define STOCK00_H_

#include <string>  

class Stock  // class declaration
{
private: 
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() { total_val = shares * share_val; }
public:
    void acquire(const std::string & co, long n, double pr);
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
};    // note semicolon at the end

#endif

使用类对象的程序可直接访问public部分,但只能通过public函数(或友元函数)来访问对象中的private成员。

实现类成员函数(双冒号::)

#include <iostream>
#include "stock00.h"

void Stock::acquire(const std::string & co, long n, double pr)
{
    company = co;
    if (n < 0)
    {
        std::cout << "Number of shares can't be negative; "
                  << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}

void Stock::buy(long num, double price)
{
     if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. "
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    std::cout << "Company: " << company
              << "  Shares: " << shares << '\n'
              << "  Share Price: $" << share_val
              << "  Total Worth: $" << total_val << '\n';
}

构造函数和析构函数

具体请看例子

#include <iostream>
#include "stock10.h"

// constructors (verbose versions)
Stock::Stock()        //默认构造函数
{
    std::cout << "Default constructor called\n";
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

Stock::Stock(const std::string & co, long n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    company = co;

    if (n < 0)
    {
        std::cout << "Number of shares can't be negative; "
                   << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}
// class destructor
Stock::~Stock()        //析构函数
{
    std::cout << "Bye, " << company << "!\n";
}

// other methods
void Stock::buy(long num, double price)
{
     if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. "
             << "Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! "
             << "Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    using std::cout;
    using std::ios_base;
    // set format to #.###
    ios_base::fmtflags orig = 
        cout.setf(ios_base::fixed, ios_base::floatfield); 
    std::streamsize prec = cout.precision(3);

    cout << "Company: " << company
        << "  Shares: " << shares << '\n';
    cout << "  Share Price: $" << share_val;
    // set format to #.##
    cout.precision(2);
    cout << "  Total Worth: $" << total_val << '\n';

    // restore original format
    cout.setf(orig, ios_base::floatfield);
    cout.precision(prec);
}

构造函数的形参名不能和成员名一样,比如如下代码是错误的:

Stock::Stock(const stirng &company, long shares, double share_val)

为避免这种混乱,一种方法是在数据成员中使用m_ 前缀,或者使用 _ 后缀,比如

class Stock  // class declaration
{
private: 
    std::string m_company;
    long m_shares;
    double m_share_val;
    double m_total_val;
    ……

或者

class Stock  // class declaration
{
private: 
    std::string company_;
    long shares_;
    double share_val_;
    double total_val_;
    ……

C++ this

this 是 C++ 中的一个关键字,也是一个 const 指针,它指向当前对象,通过它可以访问当前对象的所有成员。

#include <iostream>
using namespace std;
class Student{
    public:
    void setname(char *name);
    void setage(int age);
    void setscore(float score);
    void show();
    private:
    char *name;
    int age;
    float score;
};
void Student::setname(char *name){
    this->name = name;
}
void Student::setage(int age){
    this->age = age;
}
void Student::setscore(float score){
    this->score = score;
}
void Student::show(){
    cout<<this->name<<"的年龄是"<<this->age<<",成绩是"<<this->score<<endl;
}
int main(){
    Student *pstu = new Student;
    pstu -> setname("李华");
    pstu -> setage(16);
    pstu -> setscore(96.5);
    pstu -> show();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值