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. JAVA TCP/IP网络通讯编程(二)

    一个实例通过client端和server端通讯 客户端通过TCP/IP传输资源文件,比如图片,文字,音频,视频等..... 服务端接受到文件存入本地磁盘,返回接受到:“收到来自于"+s.ge ...

  2. 理解 Redux 的中间件

    将该思想抽象出来,其实和 Redux 就无关了.问题变成,怎样实现在截获函数的执行,以在其执行前后添加自己的逻辑. 为了演示,我们准备如下的示例代码来模拟 Redux dispatch action ...

  3. Java 爬虫遇到需要登录的网站,该怎么办?

    这是 Java 网络爬虫系列博文的第二篇,在上一篇 Java 网络爬虫,就是这么的简单 中,我们简单的学习了一下如何利用 Java 进行网络爬虫.在这一篇中我们将简单的聊一聊在网络爬虫时,遇到需要登录 ...

  4. 使用jsr303实现数据校验

    除了前端的js验证,服务端也可加入数据验证,springmvc中有两种方式可以验证输入 利用spring自带的验证框架 利用jsr303实现 jsr303实现数据校验 jsr303是java为bean ...

  5. Hyper-V虚拟机win7网络红叉,无法上网解决方法

    之前一直都是玩Vmware虚拟机,后来win8之后的系统有Hyper-V虚拟机就开始接触了. Windows 中内置的Hyper-V管理器可以说是给很多人带来了惊喜!至少运行的流畅程度要比Vmware ...

  6. Linux上安装jdk1.8和配置环境变量

    前言 Linux 上安装jdk1.8 和配置环境变量,参考相关文档,本人在此总结,操作归纳如下. 第一步:创建jdk安装目录(该/usr/local/src 目录是空的,最好把我们自己下载的放到这,容 ...

  7. Chrome插件开发(一)

    作为一个开发人员,我们在日常工作中肯定会用到 Chrome 浏览器,同时也会用到谷歌的一些插件,比如 Tampermonkey,AdBlock等,在之前的文章本人还是用了 Tampermonkey,传 ...

  8. C#通过对象属性名修改值

    摘自:csdn 给一个对象属性赋值可以通过PropertyInfo.SetValue()方式进行赋值,但要注意值的类型要与属性保持一致.    创建对象实例的两种方法: 1. var obj = As ...

  9. 单元测试实践(SpringCloud+Junit5+Mockito+DataMocker)

    网上看过一句话,单元测试就像早睡早起,每个人都说好,但是很少有人做到.从这么多年的项目经历亲身证明,是真的. 这次借着项目内实施单元测试的机会,记录实施的过程和一些总结经验. 项目情况 首先是背景,项 ...

  10. 彻底修改eclipse中项目的名称

    需要四个步骤: 一.右键工程:Refactor->Rename,或选中工程按F2,修改名称 二.修改项目目录下:.project文件 三.项目右键属性 --> Web Project Se ...