c++ 类

1 篇文章 0 订阅

C ++ 类

@(C/C++)[c++, 类]

1 类的定义/构造

1.1 关于类的理解

★关于类的理解

关于类的理解 (1) \

类,也就是带有函数的结构体,即,既有”名词”(成员变量),也有”动词”(成员函数).

1.2 类的定义

类的定义
nihao

  注意,这种定义方式,成员函数写在了类的里面。还有一种方式是将函数原型写在里面,
函数定义写在外面的。见后面

这里写图片描述

所谓,不过是以形式自定义的新的特殊的类型。就像int double char。说它特殊,是因为,还带有函数。

定义变量的过程称为实例化,所定义的变量称为对象

对象的内存空间
 ◆对象的大小 = 所有成员变量的大小之和(上述例子例子中是两个整型之和)
 ◆对于上述例子中的CRectangle类的对象, sizeof(CRectangle) = 8

每个对象各有自己的存储空间
 ◆一个对象的某个成员变量被改变, 不会影响到其他的对象

类的第二种定义方式
这里写图片描述

  注意,成员函数仅仅在内部声明,而在外部定义

2 类成员的可访问范围

关键字 – 类成员可被访问的范围
private :指定私有成员, 只能在成员函数内被访问, 注意此为缺省设定,也就是,若没指定访问范围,就是默认private
public:指定公有成员, 可以在任何地方被访问
protected:指定保护成员
三种关键字出现的次数和先后次序都没有限制

class className {
private:
           私有属性和函数
public:
           公有属性和函数
protected:
           保护属性和函数
};

3 内联成员函数/重载

和正常的成员函数以及重载是一样的.
使用缺省参数要注意避免有函数重载时的二义性

class Location {
private:
    int x, y;
public:
    void init( int x =0, int y = 0 );
    void valueX( int val = 0 ) { x = val; }
    int valueX() { return x; }
};
Location A;
A.valueX(); //错误, 编译器无法判断调用哪个

3 构造函数

定义
成员函数的一种
 ★ 名字与类名相同,可以有参数,不能有返回值(void也不行)
 ★ 作用是对对象进行初始化,如给成员变量赋初值
 ★ 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
    ☆默认构造函数无参数,不做任何操作
意义
1) 构造函数执行必要的初始化工作,有了构造函数,就不必专门再写初始化函数,也不用担心忘记调用初始化函数。
2) 有时对象没被初始化就使用,会导致程序出错。因而引进构造函数

4 复制构造函数

4.1 复制构造函数的定义

★ 只有一个参数,即对同类对象的引用
★ 形如 X::X( X& )或X::X(const X &), 二者选一, 后者能以常量对象作为参数
★ 如果没有定义复制构造函数,那么编译器生成默认复制构造函数默认的复制构造函数完成复制功能 i.e换句话说, 自己编写的复制构造函数不一定具有复制功能的!

4.2 复制构造函数的作用

1) 当用一个对象去初始化同类的另一个对象时。

Complex c2(c1);
Complex c2 = c1; //初始化语句,非赋值语句

上面两个语句等价

2) 如果某函数有一个参数是类 A 的对象, 那么该函数被调用时,类A的复制构造函数将被调用。

class A 
{ 
    public: 
    A() { }; 
    A( A & a){
             cout << "Copy constructor called" <<endl; 
     } 
 };
void Func(A a1){ }
  //实参把值传递过去时(i.e 赋值/初始化形参),用的是复制构造函数
int main(){
A a2;
Func(a2);
return 0;
}

注意, 形参的值是由复制构造函数给予的,而 复制构造函数是自己编写的, 所以形参的值并不一定等于实参了

3) 如果函数的返回值是类A的对象时,则函数返回时,类A的复制构造函 数被调用:

class A
{
    public:
    int v;
    A(int n) { v = n; };
    A( const A & a) {
        v = a.v;
        cout << "Copy constructor called" <<endl;
    }% 自己写的复制构造函数
};

A Func() {
        A b(4);
        return b;
}
int main() {
    cout << Func().v << endl;
    %Func()会产生一个返回的临时对象,这个对象的值是由复制构造函数给予的,其中复制构造函数的参数是 b .
    return 0;
}

注意 Func()会产生一个返回的临时对象.

输出结果:
Copy constructor called ,因为调用了复制构造函数
4 因为用了cout

5 类型转换构造函数

目的
 •实现类型的自动转换 特点
特点
 •只有一个参数,(但是不能是自身类的引用或者常引用,因为那就成了复制构造函数)
 •不是复制构造函数
编译系统会自动调用转换构造函数, 建立一个 临时对象 / 临时变量

6 析构函数

6.1 析构函数的构造

 • 成员函数的一种
 • 名字与类名相同
 • 在前面加 ‘~’
 • 没有参数和返回值
 • 一个类最多只有一个析构函数 

6.2 析构函数的意义

对象消亡时 自动被调用, 在对象消亡前做善后工作释放分配的空间等 (若不及时释放消亡的对象占用的空间,则会浪费大量空间,造成内存泄漏.)

6.3 析构函数的特点

★ 定义类时没写析构函数, 则编译器生成缺省析构函数
★ 不涉及释放用户申请的内存释放等清理工作(也就是如果用了new申请内存, 一定要自己编个析构函数,用delete释放掉)
★ 定义了析构函数, 则编译器不生成缺省析构函数

class String{
    private :
        char * p;
    public:
        String () {
        p = new char[10];
        }
        ~ String ();
};
String ::~ String() {
        delete [] p;
}

6.4 析构函数和数组

对象数组生命期结束时
对象数组的每个元素的析构函数都会被调用(很显然的事)

class Ctest {
   public:
       ~Ctest() { cout<< "destructor called" << endl; }
}; 

int main () {
    Ctest array[2];
    cout << "End Main" << endl;
    return 0;
}   

输出:
End Main
destructor called
destructor called
析构函数内容输出了两次, 因为对于对象数组中每个对象都使用了析构函数.

6.5 析构函数和运算符 delete

delete 运算导致析构函数调用
1)
Ctest * pTest;
pTest = new Ctest; //构造函数调用
delete pTest; //析构函数调用
2)
pTest = new Ctest[3]; //构造函数调用3次
delete [] pTest; //析构函数调用3次

以下代码是用来探知,析构函数和构造函数的机制

class Demo {
        int id;
        public:
        Demo( int i ){
                id = i;
                cout << “id=” << id << “ Constructed” << endl;
        }
        ~Demo(){
            cout << “id=” << id << “ Destructed” << endl;
        }
};
Demo d1(1);
void Func()
{
    static Demo d2(2);
    Demo d3(3);
    cout << “Func” << endl;
}
int main ()
{
    Demo d4(4);
    d4 = 6;
    cout << “main” << endl;
    { Demo d5(5); }
    Func();
    cout << “main ends” << endl;
    return 0;
}

输出:
id=1 Constructed
id=4 Constructed
id=6 Constructed
id=6 Destructed
main
id=5 Constructed
id=5 Destructed
id=2 Constructed
id=3 Constructed
Func
id=3 Destructed
main ends
id=6 Destructed
id=2 Destructed
id=1 Destructed

//c++机制,最后一起析构时,后构造的先析构
注意,在不同的编译器中,构造函数和析构函数的表现可能不同.

7 静态成员/函数

7.1 静态成员的构建

★静态成员的构建:
在说明前面加了static关键字的成员。

class CRectangle 
{ 
    private: 
        int w, h; 
        static int nTotalArea; //静态成员变量 
        static int nTotalNumber; 
    public: 
        CRectangle(int w_,int h_); 
        ~CRectangle(); 
        static void  PrintTotal(); 
        //静态成员函数 
};

7.2 静态成员的特点

★静态成员--变量--的特点:
普通成员变量每个对象有各自的一份
而静态成员变量所有的此类对象一共就一份,为所有对象共享。

注意,sizeof运算符不会计算静态成员变量。

class CMyclass
{
     int n;
     static int s;
};

sizeof( CMyclass ) = 4, Why?
因为,静态成员变量并不是放在所定义的对象的内部,而是放在某个特定的内存空间,为所有此类对象所共享.

★静态成员--函数--的特点:
普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用与某个对象

综上, 静态成员不需要通过对象就能访问 ,这点对于普通成员是不可能的.(当然,也可以通过特定对象进行访问,但是并不意味着作用于特定对象) 因此,静态成员的访问可以有一下几种形式
1) 类名::成员名
CRectangle::PrintTotal();
这种方式对于普通成员函数进行访问是不可能
2) 对象名.成员名
CRectangle r; r.PrintTotal();
虽然通过对象进行访问,但是并不意味着此函数作用于此对象, 因为此函数是静态成员函数,
3) 指针->成员名
CRectangle * p = &r; p->PrintTotal();
同理, 不意味着作用于某一特定对象.
4) 引用.成员名
CRectangle & ref = r; int n = ref.nTotalNumber
同理, 不意味着作用于特定某一对象.

在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数。
因为.静态成员函数并不具体作用与某一特定对象,若包含非静态成员变量,则修改的此变量属于哪一个对象???,对此无法解释的通.

8 成员对象&封闭类

成员对象: 一个类的成员变量是另一个类的对象包含成员对象 的类叫 封闭类 (Enclosing)

class CTyre //轮胎类
{ 
    private:
        int radius; //半径
        int width; //宽度
    public:
        CTyre(int r, int w):radius(r), width(w) { }%构造函数
};
class CEngine //引擎类
{ 
};

注意: 新的构造函数初始化方式
CTyre(int r, int w):radius(r), width(w) { }

class CTyre //轮胎类
{
        public:
            CTyre() { cout << "CTyre contructor" << endl; }//轮胎类构造
            ~CTyre() { cout << "CTyre destructor" << endl; }//轮胎类析构
};
class CEngine //引擎类
{
        public:
            CEngine() { cout << "CEngine contructor" << endl; }//引擎类构造
            ~CEngine() { cout << "CEngine destructor" << endl; }//引擎类析构
};
class CCar //汽车类
{
        private:
            CEngine engine;
            CTyre tyre;
        public:
            CCar( ) { cout << “CCar contructor” << endl; }
            ~CCar() { cout << "CCar destructor" << endl; }
};
int main(){
        CCar car;
        return 0;
}

程序的输出结果是:
CEngine contructor
CTyre contructor
CCar contructor
CCar destructor
CTyre destructor
CEngine destructor

构造时,先构造成员对象, 且按照封闭类中声明顺序构造,所以有:
CEngine contructor
CTyre contructor
CCar contructor
析构时,先析构封闭类,且成员对象析构顺序与构造顺序相反, 所以有:
CCar destructor
CTyre destructor
CEngine destructor

9 友元

9.1 友元函数

没详细看,有需要再看

一个类的友元函数可以访问该类的私有成员

9.1 友元类

A是B的友元类 -> A的成员函数可以访问B的私有成员
Note:
友元类之间的关系,不能传递, 不能继承.i.e A 是 B的
友元类, B是C的友元类, A和C之间 无关系

10 this 指针

这个的作用, C++ prime plus书上举的例子比较好
简而言之: 指向调用成员函数的对象本身(因此静态成员函数不能用this指针)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值