C++学习笔记4


目录

  • 三、类和对象

9、拷贝构造函数

10、const修饰的成员函数

  • 四、类和对象的高级应用

1、对象数组

2、this指针

3、枚举

4、静态数据成员

5、静态成员函数


  • 三、类和对象

9、拷贝构造函数

拷贝构造函数的功能是用一个已有的对象来初始化一个被创建的同样对象, 是一种特殊的构造函数, 具有一般构造函数的所有特性, 当创建一个新对象并用一个已有的对象对它进行初始化的时候系统会自动调用它; 其形参是本类对象的引用, 它的特殊功能是将参数代表的对象逐域拷贝到新创建的对象中

定义一个新的对象时,同时用已有对象给新对象赋值。此时调用的是拷贝构造函数,如果没有自行定义拷贝构造函数则调用系统默认的拷贝构造函数,但是系统默认的拷贝构造函数进行的是浅拷贝,在析构的时候回因为delete两次而出现段错误。

缺省的拷贝构造函数
                                        classname(const classname &ob)
                                        {
                                                //按数据成员的顺序逐一赋值
                                        }

自定义拷贝构造函数
                                        classname(const classname &ob)
                                        {
                                              //自定义拷贝构造函数的函数体
                                        }

//name为指针变量
STU::STU(STU &ob)//拷贝构造函数,深拷贝
{
num=ob.num;
name=new char[strlen(ob.name)+1];
strcpy(name,ob.name);
cout<<"拷贝构造函数"<<endl;
}

类里面有指针变量, 指针有申请空间, 这个时候拷贝构造函数是必须要写的。 否则会出现段错误。

函数的返回值是对象时也会调用拷贝构造

利用无名对象初始化对象, 系统不会调用拷贝构造函数
                STU A=STU(10,(char *)lucy);
                STU test(STU p){return p;}
                test(STU(4,5));

10、const修饰的成员函数

由于成员函数可以任意访问类内的任何数据成员, 但是当我们不愿意让其修改数据成员时, 我们可以用 const 修饰
成员函数, 一般形式为:
class class_name{
private:
            .....
public:
           (type) fun_name(...)const //表示函数内部不会对数据成员进行写操作(但可以读)
          {
                    ......
          }
};

这种情况, 成员函数的声明和定义 后面都要加 const

//在 getName 函数体内不能修改数据成员
char * STU::getName() const
{
    //strcpy(name,”hello”);//正确可修改 name 指向的内容, 没有修改 name 指针本身的内容
    //name=”hello”;// 出错, 修改了数据成员的值
    //num++//也出错
    return name;
}

指针指向的内存中的数据还可以修改,但是指针的指向不能修改;数组也不能修改

当数据成员类型前用 mutable 修饰时, 在 const 修饰的成员函数体内该数据成员也是可以改变的


  • 四、类和对象的高级应用

1、对象数组

对象数组, 是个数组, 数组中有若干个相同类型的对象, 在内存中连续的顺序存储;类似于结构体

STU edu[4];//实例化一个有 4 个元素的, STU 类的数组

对象数组有多少个元素就会构造多少次, 析构多少次

STU edu[4]={1,2,3,4};//这种初始化方法, 只适合有一个数据成员的情况;使用的是带参构造

STU edu[4]={STU(1),STU(2),STU(3),STU(4)};//实例化一个有 4 个元素的, STU 类的数组
                                                                                //有多个数据成员的话, 在构造函数实参地方, 继续传参如: STU(10,"lucy");

若类中含有构造函数, 那么定义对象数组时,也可通过不带参数的构造函数或带有缺省参数的构造函数给对象数组元素赋值

2、this指针

一个类有数据成员和成员函数, 数据成员是独立的(每个对象都有自己独立的存储空间) , 成员函数是共享的。

C++提供了一个特殊的对象指针---this 指针
              a、 它是成员函数所属的对象的指针, 它指向类的对象。
              b、 成员函数通过这个指针可以知道自己属于哪一个对象。
              c、 this 指针是一种隐含指针, 它隐含于每一个类的成员函数中。 即哪一个对象调用该成员函数,该 this 指针就指向那个对象。

void STU::setNum(int x)
{
    cout<<"this = "<<this<<endl;
    num=x;
}


void main()
{
    STU lucy;
    STU bob;
    lucy.setNum(200);
    bob.setNum(100);
    cout<<"&lucy = "<<&lucy<<endl;
    cout<<"lucy.getNum() = "<<lucy.getNum()<<endl;
    cout<<"&bob = "<<&bob<<endl;
    cout<<"bob.getNum() = "<<bob.getNum()<<endl;

    return 0;
}

&lucy和在setNum()中输出的this的值是一样的;bob和lucy的地址是不一样的

C++在编译过程中做了些简单的转换工作
              相应的把被调用的成员函数的定义形式进行变化。在形参列表的最前面加了STU *this
              把成员函数的调用形式进行变化,lucy.setNum(100);转换成lucy.setNum(&lucy,100);

使用this指针之后形参可以和数据成员名,例如

void STU::setNum(int num)
{
    this->num = num;
}

函数返回调用该函数的对象的引用

STU& STU::setNum(int num)
{
    this->num=num;
    return *this;
}

int main()
{
    STU ob1;
    cout<<ob1.setNum(10).getNum()<<endl;
    return 0;
}

类的普通成员函数中默认有一个隐藏的 this 指针;静态成员函数没有this指针

3、枚举

C++中的枚举跟 C 语言中的枚举一样, 只不过在 C++中定义枚举变量的时候可以不使用 enum 关键字

在默认情况下, 枚举量的值从 0 开始, 如果没有初始化, 那么它的值比前面的大 1

4、静态数据成员

在类定义中, 它的成员( 包括数据成员和成员函数) , 可以用关键字 static 声明为静态的, 这些成员称为静态成员

静态成员的特性,不管这个类创建了多少个对象, 静态成员只有一个拷贝, 这个拷贝被所有属于这个类的对象共享

静态成员包括静态数据成员和静态成员函数

静态数据成员, 在创建类的时候就有了。 普通数据成员是在定义对象的时候给其分配空间

在一个类中, 若将数据成员声明为 static, 这种成员称为静态数据成员。 (静态数据成员必须在类内声明, 在类外定义, 在类外定义的时候不能再加 static 了)

 与一般数据成员不同, 无论建立了多少个对象, 都只有一个静态数据成员的拷贝

可以认为该静态数据成员都属于该类的, 而不是具体属于某一个对象。

在类内声明带上static,在类外定义时候不能再加static;可以认为该静态数据成员都属于该类的, 而不是具体属于某一个对象。

静态数据成员为同类的所有对象共有,使用同一内存空间

在没有定义任何对象之前静态数据成员就已经存在,也可以在类外定义的同时赋初值

通过对象使用静态数据成员是不规范的, 应该通过类来使用
                      cout<<"STU::y= "<<STU::y<<endl;//规范
                      cout<<"lucy.y= "<<lucy.y<<endl;//不规范

静态数据成员一般情况放在构造函数中, 来统计我们对象的个数

public: static int total_num;

STU::STU()//无参构造函数
{
    total_num++;
    cout<<"in 无参构造函数"<<endl;
} 
STU::STU(int n)//带参构造函数
{
    total_num++;
    cout<<"in 带参构造函数"<<endl;
    num=n;
} 
STU::STU(const STU &ob)//拷贝构造函数
{
    total_num++;
    num = ob.num;
}
STU::~STU()//析构函数
{
    total_num--;
    cout<<"in 析构函数"<<endl;
}

如果静态数据成员被设置成私有的, 在类外 类名::私有成员 编译会报错;通过类名::公有静态成员函数 访问私有的静态数据成员 total_num, 可以通过公有的静态成员函数来实现静态成员函数在下节课会讲到

C++支持静态数据成员的一个主要原因是可以不必使用全局变量。 依赖于全局变量的类, 几乎都是违反面向对象
程序设计的封装原理的。

5、静态成员函数

在类定义中, 前面有 static 说明的成员函数称为静态成员函数

静态成员函数是一个成员函数, 因此可以使用”类名::”和 “对象名.”两种方法访问静态成员函数;普通成员函数, 只能通过 对象名.普通成员函数 的方法去调用

静态成员函数是一种特殊的成员函数, 它不属于某一个特定的对象。 一般而言, 静态成员函数访问的基本上是静态数据成员或全局变量不能访问普通数据成员

静态成员函数可以在类内定义。 也可以在类内声明, 类外定义, 在类外定义时不要用 static 前缀静态成员函数在类内声明的时候, 前面加 static, 在类外定义的时候前面不能加 static 关键字

使用静态成员函数的另外一个原因是, 可以用它在建立任何对象之前处理静态数据成员, 这是普通成员函数不能实现的功能

class STU{
private:
    int num;
    static int total_num;
public:
    STU();//无参构造函数
    STU(int n);//带参构造函数
    STU(const STU &ob);//拷贝构造函数
    void setNum(int n);
    int getNum();
    static int getTotalNum();
    ~STU();//析构函数
};
int STU::getTotalNum()
{
    return total_num;
}
int main()
{
    int i;
    cout<<"STU::getTotalNum()= "<<STU::getTotalNum()<<endl;
    STU lucy,bob(20);
    cout<<"STU::getTotalNum()= "<<STU::getTotalNum()<<endl;
    return 0;
}

静态成员函数, 不能访问非静态成员数据, 只能操作静态数据成员。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值