【学习笔记】C to C++ | C++ primer笔记

这篇博客是作者的C to C++学习笔记,主要关注C++ Primer的内容,包括C++标准输入输出流、引用变量、函数模板、类模板、面向对象编程、构造函数、运算符重载等主题。讲解了如何使用名字空间、引用作为别名、函数模板实现泛型编程,以及访问控制等核心概念。
摘要由CSDN通过智能技术生成

  • 文档说明:C to C++ 学习笔记自用。

Start with the class

class Name{
  Data, 
  Operation/Method,
}

class PermutationGroup{
public:
    int pN, gN; // data element type
    Permutation gp[gNMax]; //data element type
    PermutationGroup(int n); //operation; constructor of the class: same name with the class
    

    Permutation Inv(Permutation p);
    Permutation Mul(Permutation p, Permutation q);
    void PrintPermutation(Permutation p);
    void PrintPG(); // Print the permutation group
    void PrintDerivedPG(int dn);  // Print the dn-th derived permutation group
};

Main file

int main(int argn, char* argc[])
{
    int n, dn;
    if (argn<2){ n = 4; dn = 3; }
    else if (argn<3){ n = std::stoi(argc[1]); dn = 3; }
    else{ n = std::stoi(argc[1]); dn = std::stoi(argc[2]); }

    PermutationGroup g(n);
    printf("Permutation group G[%d] : totally %d permutations\n", g.pN, g.gN);
    g.PrintPG();
    g.PrintDerivedPG(dn);

    /*
    Permutation p; p.n = 4; p.p[0] = 2; p.p[1] = 3; p.p[2] = 4; p.p[3] = 1;
    g.PrintPermutation(p);
    g.PrintPermutation(g.Mul(p,p));
    g.PrintPermutation(g.Inv(p));
    g.PrintPermutation(g.Mul(p,g.Inv(p)));
    */

    return 0;
}

不带virtual:执行原来的意义
带virtual:

C++的条件编译

#if 0
#endif

#if 1
#else
#endif

#if 1
#elif
#elif
#endif

#ifdefXXX   如果已经定义了这个宏
#endif

#ifndefXXX
#else
#endif

C++标准输入输出流-名字空间

cout是标准名字空间std的一个名字,使用的时候要加上名字空间限定std::

例如std::cout

end of file in Windows: ctrl+z

文件的写入,文件的读取和输出

# include <iostream>
# include <fstream>
# include <string>

using namespace std;

int main(){
    ofstream oF("test.txt");
    oF<<3.14<<"hello world\n";
    oF.close();//关闭内容

    ifstream iF("test.txt"); //写入文件,把文件load进来
    double d;
    string str;

    iF >>d>>str;
    cout << d << " " << str<<endl;

    return 0;
}

引用变量

引用变量是其他变量的别名,一旦引用了一个变量,就不能引用其他变量

int &r = a; //r 是a的引用变量,也就是说,r和a是一样的

引用变量和被引用变量必须同一类型;对引用变量和原变量的操作是一样的

函数的值形参

函数改变原函数:需要输入变量地址

void swap(int *x, int *y){
  int t = *x;
  *x = *y;
  *y = t;
}

函数的默认形参&函数重载

形参又默认值

默认形参必须在非默认形参右边

void print(char ch, int n=1)

允许同一作用域里面有同名的函数,形参不同即可

int add(int x, int y);
double add(double x, double y);
(double)5 //强制类型转换

函数模板

为了避免修改起来麻烦,使用函数模板,将如同double, int等的数据类型变成类型模板参数

template <typename T>//表示类型模板参数
T add(T x, T y){
  return x+y;
}

使用方法:

cout << add<int>(5,3) <<endl;
cout << add<double>(5.3,7.8) <<endl;

如果里面是int,则生成数据类型T=int的函数
字符串相加就是两个字符出链接

C++primer - page 680

  • Templates are foundation for generic programming in C++
  • If the function body is the same, only the type of input or output are different, we shall use function template
template <typename T>
int compare(const T &v1, const T &v2)
{
  if (v1<v2) return -1;
  if (v1>v2) return 1;
  return 0;
}

//usage:
compare(1,0)// T as int

vector<int> vec1{1,2,3}, vec2{4,5,6};
compare(vec1, vec2)

In the template definition, each type parameter must be preceeded by the keyword class or typename.

template <typename T, class U> calc(const T&, const U&);

Here, bothe class and typename are the same.

  • Nontype Template Parameters
    represents a value, must be constant expressions: constant for nontype integral parameter, static lifetime for pointer or reference.

Can be used when constant expressions are required.

template<unsigned N, unsigned<M> // specify the type of the nontype template
int compare(const char(&p1)[N], const char(&p2)[M]){return strcmp(p1,p2);}

类模板 - C++ primer Page 687

template<typename T> class Blob{
  public:
  private:
};

调用的时候一定要说明类型

Blob<int> ia;

用户定义类型string和vector

  • string
string s = "hello", s2("world");

cout<<s.size()<<endl; //访问字符串长度
cout<<s.substr(1,3)<<endl; //访问字符串起1尾3

用运算符对string对象进行运算,如+,[]
+进行字符串拼接,方框进行部分修改

int main(){
    string s = "hello", s2("world");
    string s4 = s+" "+s2;

    cout<<s2<<endl;
    cout<<s<<endl;

    s4[0] = 'H';
    s4[6] = 'X';
    cout<<s4<<endl;

    return 0;
}

int pos = s4.find("orl");//返回的是位置名字
cout<<pos<<endl;

s4.insert(3,"ABCDE"); //根据位置索引进行插入操作
cout<<s4<<endl;

helABCDElo world

  • vector
    向量,类似于数组,但是可以动态增长,头文件,类模板。通过实例化产生类,如vector产生数据袁术是int的vector类(向量)

可以通过vector类对象访问成员

指针和动态内存分配

# include <iostream>
using namespace std;

int main(){
    //让指针变量存放动态内存
    //堆存储区
    /* int *p = new int;//相当于分配内存
    *p = 3;
    cout<<p<<'\t'<<*p<<endl;
    delete p;//释放内存
    p = new int;
    *p = 5;
    cout<<p<<'\t'<<*p<<endl;
    delete p; */

    int n = 4;
    int *p = new int[n];
    for (int i=0;i<n;i++)
        p[i] = 2*i+1;

    char *s = (char *)p;//强制类型转换
    char ch = 'A';
    int n2 = n*sizeof(int)/sizeof(char);
    for (int i = 0;i<n2;i++)
        s[i] = ch+i;

    cout<<s<<endl;

    /* int arr[] = {10,20,30,40};
    int *p = arr; //定义p就是arr的地址
    cout<<*(p+2)<<'\t'<<p[2]<<'\t'<<arr[2]<<endl;

    for (int *q=p+4; p<q;p++)
        cout<<*p<<'\t';
    cout <<'\n';
 */
    return 0;
}
delete []    q;//表示释放这个变量的所有内存

面向对象编程

从多个对象当中抽取概念,形成“类”,其中有“属性”和“行为功能”。

从每个类中产生实例

某些概念当中存在某种关系,比如包含关系

同时存在继承(派生关系)

this 指针

stu.print();//print(&stu)

C++ primer - page 285

using namespace std
struct Sales_data{
  // new members: operations on Sales_data objects
  string isbn() const {return bookNo;}
  Sales_data& combine(const Sales_data&);
  double avg_price() const;
  
  // data members unchanged
  string bookNo;
  unsigned units_sold == 0;
  double revenue = 0.0;
};

//nonmember Sales_data interface functions
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data);
std::istream &read(std::istream&, Sales_data&);

for the member function isbn(), Member functions access the object on which they were called through an extra, implicit parameter named this.

when we call

total.isbn()

We’re actually calling

// pseudo-code illustration
Sales_Data::isbn(&total)

which calls the isbn member of Sales_data passing the address of total;

  • Const after parameter list
    Now look at the const after the parameter list
string isbn() const {return bookNo;}

It means that this is a pointer to a const variable, const member functions cannot change the object on which they are called. The called member is protected. The isbn() may read out but cannot change or write in any.
A member defined outside the class must include the name of the class

double Sales_data::avg_price() const{
  if (units_sold)
    return revenue/units_sold;
  else
    return 0;
}
  • Function returning “This object” page 289
    the combine function is used to combine a new data into a Sales_data, it is defined as:
// returning the address of the sales_data type, inputting a Sales_data type address
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
  units_sold += rhs.units_sold;
  revenue += rhs.revenue;
  return *this; //return the object whihc the function was called
}// we need to use "this" to access the object as a whole

访问控制 (access control)

struct里面成员默认是public

class里面成员默认是private

一般来说让成员private,让函数public

# include <iostream>
# include <string>

using namespace std;

class student
{
    string name;
    double score;
public://公开化
    void print(){//隐含了一个this指针
    cout << this->name<< " "<< this->score<<endl;}
    string get_name(){return name;}
    double get_score(){return score;}
    void set_name(string n){name = n;}
    void set_score(double s){score = s;}//取代疏解访问
};

int main(){//main是外部函数,而如果没有public,则不能访问stu对象当中的private成员name和score
    student stu;
    //stu.name  = "Li Ping";
    //stu.score = 78.5;
    stu.set_name("Liping");
    stu.set_score(78.5);
    stu.print();
    return 0;
}

C++ primer - page 297 (Access control & encapsulation)

  • public: accessible to all parts of the program. They define the interface to the access
  • private: accessible to member functions, not to codes in the file. Private sections encapsulate the implementation
using namespace std;

class Sales_data{
public://access specifier,part of the interface follows
  Sales_data() = default; //using the synthesized default constructor
  Sales_data(const string &s, unsigned n, double p):
         bookNo(s),units_sold(n),revenue(p*n){}//reading in the ISBN, the units sold, and the single book price
         // the constructor initializer list
  Sales_data(istream &);//from which to read in a function, the rest is outside the body
  Sales_data(const std::string &s): bookNo(s) {}
  string isbn()const {return bookNo;}
  Sales_data &combine(const Sales_data&);
  
private://part of the implementation follows
  double avg_price() const {return units_sold?revenue/units_sold:0;}
  string bookNo;
  unsigned unites_sold = 0;
  double revenue = 0.0;
}

for struct, non-specified(by access) members are public, while class has them as private.F

  • Friends(友元函数)
    functions that are not members or interface of the class, but can also access the nonpublic members of the class.

A friend declaration only specifies access, not a general declaration of the function.

Provide separate declarations for add, print, read functions to use outside the class.

using namespace std;

class Sales_data{

friend Sales_data add(const Sales_data&, const Sales_data&);
friend std::ostream &print(std::ostream&, const Sales_data);
friend std::istream &read(std::istream&, Sales_data&);
public://access specifier,part of the interface follows
  Sales_data() = default; //using the synthesized default constructor
  Sales_data(const string &s, unsigned n, double p):
         bookNo(s),units_sold(n),revenue(p*n){}//reading in the ISBN, the units sold, and the single book price
         // the constructor initializer list
  Sales_data(istream &);//from which to read in a function, the rest is outside the body
  Sales_data(const std::string &s): bookNo(s) {}
  string isbn()const {return bookNo;}
  Sales_data &combine(const Sales_data&);
  
private://part of the implementation follows
  double avg_price() const {return units_sold?revenue/units_sold:0;}
  string bookNo;
  unsigned unites_sold = 0;
  double revenue = 0.0;
}

// nonmember parts of the Sales_data interface
Sales_data add(const Sales_data&, const Sales_data&);
std::ostream &print(std::ostream&, const Sales_data);
std::istream &read(std::istream&, Sales_data&);

构造函数(constructor)

class student
{
    string name;
    double score;
public://公开化
    //student(){} //如果没有自己定义构造函数,则这么生成
    student(){cout <<"构造函数"<<endl;}
    
    void print(){//隐含了一个this指针
    cout << this->name<< " "<< this->score<<endl;}
    string get_name(){return name;}
    double get_score(){return score;}
    void set_name(string n){name = n;}
    void set_score(double s){score = s;}//取代疏解访问
};

int main(){
  student stu; //创建一个类对象的时候自动调用成为构造函数的成员函数
  stu.print();
}

如果没有自己创建构造函数,那么程序会自动创建
构造函数:函数名和类名相同且无返回类型的成员函数

student(){}

C++ primer - page 291

  • The job of constructors is to initialize the data members of a class object, having the same name as the class name.
  • (Synthesized) Default constructor: one that takes no arguments
  • Constructors have no return type
using namespace std;
struct Sales_data {
  //constructors added;
  Sales_data() = default; //using the synthesized default constructor
  Sales_data(const string &s, unsigned n, double p):
         bookNo(s),units_sold(n),revenue(p*n){}//reading in the ISBN, the units sold, and the single book price
         // the constructor initializer list
  Sales_data(istream &);//from which to read in a function, the rest is outside the body
}

We write

Sales_data() = default;

because we want to provide it as a constructor as well.

  • Defining a Constructor outside the Class Body
    After we have defined the constructor with istream, we need to define how to works outside the class
using namespace std
Sales_data::Sales_data(istream &is)
{
  read(is, *this); //read in a transaction
}

运算符重载

如果想要让cout<<stu输出整个信息,就需要对<<运算符进行重载;

operator<<(ostream &o, student stu){//返回类型:对象本身&o
  cout<<s.name<<" " <<s.score<<endl;
  return 0;
}//此时student是struct

//对于class student,name和score是private数据类型,
//但是可以添加友元函数
class student{
  private:
    string name;
    double score;
    
  public: 
  student(string n,double s){
    name = n; score = s;
  }
  //友元函数
  friend ostream& operator<<(ostream &o,student s);
};//就可以用了

//输入流对象也是一样

另外的Introduction to Classes (C++ primer CH7)

  • defining read and print functions with iostream
/*
IO classes cannot be copied, but can only be accessed with reference
reading and writing to a stream changes the stream, so no const
*/
istream &read(istream &is, Sales_data &item)
{
  double price = 0;
  is>>item.bookNo >> item.units_sold>>price;
  item.revenue = price*item.units_sold;
  return is;
}

ostream &print(ostream &os, const Sales_data &item)
{
  os << item.isbn() << " " << item.units_sold << " " 
      <<item.revenue <<" " <<item.avg_price();
  return os;
}

调用的时候is用cin,cout等stream代替

  • add function
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
  Sales_data sum = lhs;//copy lhs to sum
  sum.combine(rhs); // add data members from rhs to sum
  return sum;
}

Class members revisited - page 300

define a new class, the new alias of pos hides how contents and other information are constructed, only showing users the pos as public member

using namespace std
class Screen{
public:
  typedef string::size_type pos;
  //using pos = string::size_type;
  
  Screen() = default; //needed a default constructor
  Screen(pos ht, pos wd, char c): height(ht), width(wd), contents(ht*wd,c){}
  char get()const {return contents[cursor];} //implicitly inline,returns the character currently denoted by the cursor
  inline char get(pos ht, pos wd) const; //explicitly inline, returns the character at the given row and column
  Screen &move(pos r, pos c); // be made inline later
  
  void some_member() const;//used to track how many times the members are called
  
  Screen &set(char);
  Screen &set(pos,pos,char);
  
  Screen &display(ostream &os){do_display(os);return *this;}
  const Screen &display(ostream &os) const {do_display(os);return *this;}
  



private://page(306)
  pos cursor = 0;
  pos height = 0, width = 0;
  string contents;
  mutable size_t access_ctr;//mutable variables may change even in a const object
  void do_display(ostream) const{os<<contents;}
};

void Screen::some_member()const
{
  ++access_ctr; // keep count of the calls to any member functions
}

inline Screen &Screen::set(char c)
{
  contents[cursor] = c;
  return *this;
}

inline Screen &Screen::set(pos r, pos col, char ch)
{
  contents[r*width+col] = ch;
  return *this;
}

our second constructor*(Screen(pos ht, pos wd, char c))* implicitly uses the in-class initializer for the cursor member, if we do not, we explicitly initialize cursor along with others.

  • Making members inline
inline
Screen &Screen::move(pos r,pos c)
{
  pos row = r*width;//the row location
  cursor = row+c;//move cursor to the column within that row
  return *this;
}

char Screen::get(pos r,pos c) const //declared as inline in the class
{
  pos row = r*width;//the row location
  return contents[row+c];//return character at the given column
}
  • Overloading Member Functions
Screen myscreen;//实例化
char ch = myscreen.get()//returns the character pointed by the cursor now
ch = myscreen.get(0,0)//returns the character at the position (0,0)
  • Class declarations
    We can declare a class before defining it, but we can only do a limited number of operations based on it.
class Screen;
class Link_screen{
  Screen window;
  Link_screen *next;
  Link_screen *prev;
};

Friendship revisited

Object-Oriented Programming (C++ primer CH15)

  • Class Quote: base class, represent undiscounted books

  • Class Bulk_quote: represent books that can be sold with a quantity discount, inherits from Quote
    two member functions:

  • isbn(), return the ISBN, not depending on the specifics of classes

  • net_price(size_t), depends on the specific class
    Derived class must declare all the virtual functions it inherits from the root function

using namespace std
class Quote{
public:
  Quote() = default;
  Quote(const string &book, double sales_price): bookNo(book),price(sales_price){}
  
  
  string isbn() const;
  virtual double net_price(std::size_t n) const {return n*price};
  //needed even they don't work  

private:
  string bookNo;//ISBN of the item
protected:
  double price = 0.0;
};

Derived class must use a base-class constructor to initialize its base-class part.

virtual is used for derived classes to define for themselves, as in Bulk_quote:

class Bulk_quote: public Quote{//stating the base class
public:
  Bulk_Quote() = default;
  Bulk_Quote(const string &book, double p,std::size_t qty,double disc):
            Quote(book,p),min_qty(qty),discount(disc){};
  double net_price(std::size_t) const override;//explicitly note that it intends to override
  
private:
  std::size_t min_qty = 0; //minimum purchase for the discount to apply
  double discount = 0.0;//fractional discount
};
  • Dynamic Binding
    a function can use either type of Quote or Bulk_Quote to implement(running time binding)
double print_total(ostream &os, const Quote &item, size_t n)
{
  double ret = item.net_prize(n);
  os<<"ISBN: "<<item.isbn()<<"# sold: "<<n<<"total due: "<< ret<<endl;
  return ret;
}
  • Protected:
    Private is members the base class does not want even the inherited class to access. But protected is for the members accessible by inherited classes but not others.

  • Pointers with the inherited classes

Quote item;
Bulk_quote bulk;
Quote *p = &item;//p points to a Quote object
p = &bulk;// p points to the Quote part of bulk
Quote &r = bulk; // r bound to the Quote part of bulk

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值