1. 类
*在C++中,struct和class没有明显差别,不同C#,class一定要new(手动开辟内存)出来
struct Hero
{
  char name[64];
  int sex;
}
void print(struct Hero &h)
{
...
}
class AdvHero
{
  public:
  char name[64];
  int sex;
  void print()
  {
    cout<<name<<endl;
  }
}
int main(void)
{
  Hero h;
  strcpy(h.name,"zhangsan");
  //
  AdvHero v;//不用new出来,c++中的new另有含义
  strcpy(v.name,"lisi");
}

2. 构造函数:
class A
{
  public:
    int age;
    char* Name;
    A(int x)
    {
      age=x;
      Name =(char*)malloc(100);
    }
    ~A()
    {
      //析构函数没有形参,当对象被销毁前自动调用
      if(name!=NULL)
      {
        free(name);
      }   
    }
}
int mian()
{
  A a(10);
}
//堆栈在a被声明时,在栈中,开辟存储a的内存,含有一个int大小的,和char*一个指针大小的空间,然后在堆中,开辟100个字节的空间,用Name指向它。
//但是析构的时候,只会自动清除栈的东西,所以一定要记得释放堆中的东西。
//栈是会被压的!!

拷贝构造函数:
class Test
{
  //显式的拷贝构造函数,
  Test(const Test &anthor)//const引用,就是不能改变anthor所代表的对象的任何东西。
  {
    //...
  }
  //=赋值操作符
  void operator=(const Test &another)
  {
    //...
  }
}
//和C#不同,C#是没有拷贝构造函数的。
//
int main(void){
  Test t1;
  Test t2(t1);
  //这句话,如果=号操作没有重载,拷贝构造函数也没有重载,那么也相当于t2=t1;t1复制一份,给t2。
  //就算Test没有传入参数为Test的构造函数,也能成功。能自动将成员值拷贝过去。
  //因为有默认的拷贝构造函数
  Test t3;
  t3=t1;//这里就不是调用构造函数了,而是调用=操作函数
  //
  Test t4=func();//**这里也不会发生t4先构造,然后执行=操作,而是将func()返回的结果“转正”
  //
  t3=func();//**这里就会发生执行=操作了。而且func()返回的匿名对象会被析构掉。

}
******************************
//在C++中,struct和class没有明显差别。不同C#,class一定要new(手动开辟内存)出来。
//在classA a;这句中,已经调用了构造函数了。C#中,仅仅是声明一个空的引用变量a。
//在a=b;调用了操作符号=函数。C#中,则是引用变量a来引用b引用的对象,a和b都是引用同一个对象。
//所以C++中,对象的传参,参数返回(除非是返回堆中的对象引用),都是复制的操作,同时,复制的时候会调用默认的拷贝构造函数,出栈的时候,也会调析构函数。
//各种拷贝,析构,也是可以通过引用来优化的地方!
//这是C++和大多数语言的不同。
******************************

3. 深拷贝和浅拷贝
class Teacher
{
  int m_id;
  char*m_name;
  public:
    Teacher(int id,char *name)//这就算深拷贝了,浅拷贝的话,m_name的值和name是一样,指向同一块内存。
    {
      m_id=id;
      int len = strlen(name);
      m_name=(char*)malloc(len+1);//因为最后要以\0标志字符串结束,所以+1
      strcpy(m_name,name);
    }
    //一般的浅拷贝构造函数
    Teacher(const teacher&a)
    {
      mid=a.mid;
      m_name=a.m_name;
    }
    //一般的浅拷贝构造函数
    Teacher(const teacher&a)
    {
      //按Teacher(int id,char *name)来写。
    }
    ~Teacher()
    {
      if(m_name!=NULL)
      {
        free(m_name);//记得释放堆上的内存
      }
    }
}
//*****free是不能重复对同一指针值(内存地址)执行两次的。
//*****所以,见到类中,有指针成员,一定要特别留意,先看析构函数,会不会有可能free同一个内存地址;然后考虑要不要深拷贝。
//*****浅拷贝风险,就是有指针成员时,析构时释放堆内存,可能会重复释放内存。

4. 构造函数的初始化列表
class B
{
  public:
    B(A &a1,A&a2,int m):m_a1(a1),m_a2(a2),m_m(m)//常量成员的赋值,只能放在初始化列表中
    {
      //如果这使用m_a1=a1,显然达不到调用A的构造函数的目的,只是调了A的=操作符函数
      //如果这里写m_a1(a1),会语法错误,将m_a1当做了函数使用了
    }
  private:
    A m_a1;
    A m_a2;
    int a=3;//很多编译器不支持这种写法,所以尽量要写到构造函数中
    const int m_m;//只能赋值一次,而且不能const int m_m=3;因为有些编译器不支持
}
//在构造的时候,先执行A的构造两次,然后执行B构造函数体;在析构的时候,先析构m_a1和m_a2,然后再执行B析构的函数体。

5. 静态成员
void test()
{
    int static a=10;//这句话只会在第一次执行的时候,给a赋值,因为a在运行初阶段就放在静态区了。
    a++;
}

class A
{
  public:
    A()
    {
      //...
    }
    static int m_c;//也是在程序运行之初放在静态区的
}
**************************************************************
int AA::m_c=100;//在声明类的时候,就给静态变量赋初值了。
*记得#ifndef #endif

void funtion()
{
  AA:m_c=100;//不用写成 int AA:m_c=100;这是在方法之外写的。
}

6. this指针
//对于一个类,只有非静态字段才属于这个对象(才在这个对象的内存中),static成员在静态区,而且方法也不在这个对象的内存区域中。
//那为什么a.getPrivateProperty()能获得a的私有成员呢,但是getPrivateProperty()方法不在a的内存区域内???
class Test
{
  private:
    int n1;
    public:
      Test(int i)
      {
        n1=i;
      }
      int getn1()
      {  
         return n1;
         //等价于return this->n1;
      }

      int getn2() const //加个const,防止这个方法内改变this所指向的内容,相当于const Test * const this(指向常量的常指针,相当于常引用了)
      {
      }

      static void print()
      {//...}
}

int main(void){

  Test a(10);
  a.getn1();
  Test::Print();

}

通过编译后,变为:
struct Test
{
  int n1;
};
void Test_initialize(struct Test *pThis,int i)
{
  pThis->n1=i;
}
int Test_getn1(struct Test *pThis)
{
  return pThis-<n1;
}
void Test_Print(){//.....}

int main{
  Test a;
  Test_initialize(&a,10);
  Test_getn1(&a);
  Test_Print();

}
//再次,在C++中,struct和class没有明显差别。

7. 返回对象本身,主要可以用于链式操作
class Test
{
  private :
    int a;
  public:
    &Text Add(Text &another)
    {
      this->a=this->a+another.a;
      return *this;
    }
}
//能达到每次连加都会改变自身,又不用复制。

8. 友元函数
class Point
{
  private :
    double x;
    double y;
    //
    friend double PointDistance(const Point &p1,const Point &p2);
    //也能friend double Calculater::PointDistance(const Point &p1,const Point &p2);
    //Calculater类一定要在Point声明之前声明好
  public:
    Point(double x,double y)
    {
      this->x=x;
      //...
    }
    double getX()
    {
      return this->x;
      //以匿名的方式,返回x的复制值。
    }
    double getY(){ //...}
}
double PointDistance2(const Point &p1,const Point &p2)
{
  //有getX(),getY()的操作,调用方法就有压栈出栈的过程,效率比p1.x低多了。
}

如果在类中声明有:
friend double PointDistance(const Point &p1,const Point &p2); 那么就可以p1.x,使用私有成员了。就像PointDistance是类中的成员函数一样。
**因为友元通常会破坏封装性,所以不推荐使用。

9. 声明。声明的作用,就是预先告知有这个东西,其地方要使用它,必须要有预先告知。比如:
  double PointDistance2(const Point &p1,const Point &p2);
如果这个函数声明前,没有通过头文件,或者其他办法,获取到Point 的声明,那么编译不过的。
正确的办法:
  class Point;//这个也是声明
  double PointDistance2(const Point &p1,const Point &p2);
****这也是C#和C++不同的地方,C#是声明和实现放在一起,而且不分先后顺序。

10. 友元类
class B;
  class A
  {
    friend class B;
    priviate : int a;
  }
class B
{
  private : int b;
  public:
    B& addA(const A &a)
    {
      this->b= this->b+a.a;
      return *this;
    }
}
**因为友元通常会破坏封装性,所以不推荐使用。

11. 操作符重载
//
new和delete也是操作符,也能重载的
//
*通常会重载“=”号,用于深拷贝
*通常也会重载+-号,用于一些字段的加减
class Complex
{
   private:
    int a;
    int b;
   public:
    Complex operator +(const Complex &b)
    {
      Complex c;
      c.a=this->a+b.a;
      c.b=this->b+b.a;
      return c;
    }
        //如果写在外边的话Complex operator +(const Complex &a, const Complex &b); 调用也可以Complex c3= operator+(c1,c2);

    Complex& operator +=(const Complex &b)
    {
      c.a=this->a+b.a;
      c.b=this->b+b.a;
      return this;
    }

    //后++运算,加const,防止拼命++下去
    const Complex operator ++(int)//要有个int填坑
    {
      Complex temp(*this);
      this.a++;
      this.b++; 
      return temp;
    }
    //为了能cout << complex,但这里c1.operator<<(os);或者c1<<cout;太别扭
    //所以只能写全局了
    ostream & operator <<(ostream &os)
    {
      os<<this->a<<this->b;
      return os;
    }
}

ostream & operator <<(ostream &os,Complex &c);//这样就可以cout<<c了;

12. 任何传入类的字符串指针,都要考虑深拷贝和析构,否则如果外边释放了内存,那么使用会出错。

13. ***************************重写无参构造,=操作符必要的注意事项***************************
等号操作符注意事项:
class A
{
  public:
    char*Name;
    A(const A &a)
    {
      this->name=new char[strlen(a.Name)];
      if(this->name!=NULL){
        strcpy(this->Name,a.Name);
      }
    }
    //遇到有成员指针是开辟堆内存的,一定要重写=,重写无参构造,重写析构
    A & operator=(const A &a)
    {
      if(this==*a) { return *a;}
      //
      if(this->name!=NULL)
      {
        delete[] this->name;
        this->name = NULL;
      }
      //重新开辟
      this->name=new char[strlen(a.Name)];
      if(this->name!=NULL){
          strcpy(this->Name,a.Name);
      }
    }
    ~A()
    {
      if(this->name==NULL)
      {
        delete[] this->name;
        this->name = NULL;
      }
    }
}

14. []操作符重载,通常返回引用,因为a[i]应该既可以取,也可以修改才行。
char & operator[](const int &i)
{
  return this->Name[i];
}

15. ()操作符重载
int main(void)
{
  typeA a ;
  a();//这里是由于操作符重载,所以可以这样
}

16. const引用和const函数
class A
{
  public:
    int getLenght1()//实际上会编译为 int getLenght(int *const this),const指针,指向不可变
    {

    }
    //
    int getLenght2() const //实际上为const int *const this,相当于const引用,指向内容不可变,指向不可变 , 相当于const A &a
    {

    }
}

// 不能通过const引用修改变量的值
void function(const A &a) //为了保护a不在方法中被改变
{
  a.getLenght1(); //这里出错,用高安全的引用作为实参,调用低安全形参的函数。
  a.getLenght2(); //这里才不会出错
}

17.  类模板

C#

public class Airport<T> where T:Plane  //能限定T的类型

{

  //..

}

template<class T> class Person

{

  public:

    T mId;

    T mAge;

    Person(T mld,TmAge);

    template<class T> friend ostream& operator<<(ostream& os,Person<T> &p);//windows下

      friend ostream& operator<<<T>(ostream& os,Person<T> &p);//linux下

}

//声明和实现分开

temple<class T> Person<T>::Person(T mld,TmAge)//十分麻烦的写法

{

}

//

template<class T> ostream& operator<<(ostream& os,Person<T> &p)

{

}

最好的写法:

//

template<class T> class Person;//先额外声明

template<class T>void Print(Person<T> &p);//先额外声明

template<class T> Person

{

  public :

    friend void Print<T>(Person<T> &p);

}

//

template<class T>void Print(Person<T> &p)

{

  //....

}

//

继承

class SubPerson:public Person<int>

{

}

18.  类模板的声明部分和实现部分分离,然后使用的坑

//C++编译器,对cpp文件独立编译,不会看文件之间的关联有没有出错

//C++编译器在编译的时候,发现一个函数调用,在当前文件找不到,那么先留坑,让后面连接器找。

//模板类,会进行两次编译,第一次对模板;第二次,在发现调用的时候,再去找模板,再编译多一个具体的函数出来。

(include<头文件>只做内容替换,不编译)

//所以,函数模板的实现部分,一定要在使用前先编译好。那么:可以不包含头文件,直接包含源文件

#include "Person.cpp"

//还有业界的做法就是,不要声明和实现分离,将他们写到Person.hpp;那么别人就知道是模板了。

19. 模板类的静态成员

根据上边的结论

template <class A>  class P

{

  public:

    static int a;

}

template <class A> P::a=1;

//

int main()

{

  P<int> a;

  P<char> b;

  //a.a和b.a不是共享同一个a,因为由于模板的编译方式,P<int>和P<char>可以当做两个类

}

C++学习笔记3_类.和相关函数的更多相关文章

  1. Java学习笔记——File类之文件管理和读写操作、下载图片

    Java学习笔记——File类之文件管理和读写操作.下载图片 File类的总结: 1.文件和文件夹的创建 2.文件的读取 3.文件的写入 4.文件的复制(字符流.字节流.处理流) 5.以图片地址下载图 ...

  2. APUE学习笔记3_文件IO

    APUE学习笔记3_文件IO Unix中的文件IO函数主要包括以下几个:open().read().write().lseek().close()等.这类I/O函数也被称为不带缓冲的I/O,标准I/O ...

  3. python学习笔记4_类和更抽象

    python学习笔记4_类和更抽象 一.对象 class 对象主要有三个特性,继承.封装.多态.python的核心. 1.多态.封装.继承 多态,就算不知道变量所引用的类型,还是可以操作对象,根据类型 ...

  4. Java学习笔记之---类和对象

    Java学习笔记之---类和对象 (一)类 类是一个模板,它描述一类对象的行为和状态  例如:动物类是一个类,动物们都有属性:颜色,动物们都有行为:吃饭 public class Dog { Stri ...

  5. UML学习笔记:类图

    UML学习笔记:类图 有些问题,不去解决,就永远都是问题! 类图 类图(Class Diagrame)是描述类.接口以及它们之间关系的图,用来显示系统中各个类的静态结构. 类图包含2种元素:类.接口, ...

  6. swift学习笔记3——类、结构体、枚举

    之前学习swift时的个人笔记,根据github:the-swift-programming-language-in-chinese学习.总结,将重要的内容提取,加以理解后整理为学习笔记,方便以后查询 ...

  7. Java学习笔记-File类的基本方法

    要渐渐养成写博客的习惯-----> 前段时间看Mars的java中的I/O流没怎么懂,发现I/O流好难啊.今天重新看一遍其他教学,还有书籍,做些笔记,记录下每天的学习生活. File类的一些方法 ...

  8. CSS3学习笔记——伪类hover

    最近看到一篇文章:“Transition.Transform和Animation使用简介及应用展示”    ,想看看里面 “不同缓动类效果demo”例子的效果,发现了一个问题如下: .Trans_Bo ...

  9. Java7编程 高级进阶学习笔记--嵌套类

    定义: 在一个类中定义的类叫做嵌套类. 作用: 1.允许对相关类进行逻辑分组 2.增强了代码的封装性 3.使代码具有更强的可读性和维护性 使用方式: package com.cmz.baseTest; ...

随机推荐

  1. 数据库系统概论——从E-R模型到关系模型

    E-R模型和关系模型都是现实世界抽象的逻辑表示 E-R模型并不被 DBMS直接支持,更适合对现实世界建模 关系模型是 DBMS直接支持的数据模型 基本 E-R图中的元素包括实体集.联系集.属性 椭圆框 ...

  2. Go语言基础之net/http

    Go语言基础之net/http 2017年6月26日 Go语言内置的net/http包十分的优秀,提供了HTTP客户端和服务端的实现. net/http介绍 Go语言内置的net/http包提供了HT ...

  3. Android之各个版本之间的变化

    (1)android5.0 Android5.0之后隐式打开服务需要指明包名 (2)android6.0 Android6.0之后涉及隐私的权限必须动态申请 (3)android8.0 android ...

  4. Django默认权限机制介绍及实践

    演示Django版本为当前最新版本v2.2 当Django配置文件中的INSTALL_APPS包含了django.contrib.auth时,就默认启用了一个简单的权限系统,提供了为用户或组分配权限的 ...

  5. golang grpc 详解

    https://segmentfault.com/a/1190000007880647

  6. Java读源码之Thread

    前言 JDK版本:1.8 阅读了Object的源码,wait和notify方法与线程联系紧密,而且多线程已经是必备知识,那保持习惯,就从多线程的源头Thread类开始读起吧.由于该类比较长,只读重要部 ...

  7. idea tomcat提示Unable to ping server at localhost:1099

    idea启动tomcat报错Unable to ping server at localhost:1099 是 IDEA配置的jdk版本 与 tomcat的jdk版本不配导致的

  8. 转 NAT技术详解

    NAT产生背景 今天,无数快乐的互联网用户在尽情享受Internet带来的乐趣.他们浏览新闻,搜索资料,下载软件,广交新朋,分享信息,甚至于足不出户获取一切日用所需.企业利用互联网发布信息,传递资料和 ...

  9. [CF494B] Obsessive String

    Hamed has recently found a string t and suddenly became quite fond of it. He spent several days tryi ...

  10. 生产环境中利用软链接避免"rm -rf /"的方法

      1.将系统中的rm二进制文件重命名为rm_real:2.编写脚本rm_shell,rm_shell中主要包含以下内容:    2.1)路径转换模块,用于将rm_shell参数中的路径转换为绝对路径 ...