C++类与对象初步认识

C++语言概述

C++C语言的继承,它既可以进行C语言的过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。C++擅长面向对象程序设计的同时,还可以进行基于过程的程序设计,因而C++就适应的问题规模而论,大小由之。C++不仅拥有计算机高效运行的实用性特征,同时还致力于提高大规模程序的编程质量与程序设计语言的问题描述能力。


类与对象

类和对象(class)是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型。它们的关系是,对象是类的实例,类是对象的模板。对象是通过new className产生的,用来调用类的方法;类的构造方法 。


类的结构

C++使用关键字class来定义类,基本形式如下:

    class 类名  
    {  
        public:  
            //公共的行为或属性  
        private:  
            //私有的行为或属性
        protected//受保护的行为或属性
    };  

public private procted关键字规定了所在区域内数据或者函数对应的访问权限


创建一个类和对象

#include<iostream>
//定义点类
class Point {
public:
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};

//类中函数的声明
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}
int main(void)
{
    //定义两个对象
    Point p1, p2;
    p1.get_x(3);
    p1.get_y(4);
    p1.show_point();

    p2.get_x(7);
    p2.get_y(9);
    p2.show_point();
    return 0;
}

执行后的效果:

x:3
y:4
x:7
y:9
请按任意键继续. . .

其实像我们示例代码中类的函数十分简单的话,不用在类外进行声明,可直接将函数体写在类内,类似下面的写法

#include<iostream>
//定义点类
class Point {
public:
    void get_x(int xx) {
        x = xx;
    }
    void get_y(int yy) {
        y = yy;
    }
    void show_point() {
        cout << "x:" << x << endl;
        cout << "y:" << y << endl;
    }
private:
    int x, y;
};
int main(void)
{
    //定义两个对象
    Point p1, p2;
    p1.get_x(3);
    p1.get_y(4);
    p1.show_point();

    p2.get_x(7);
    p2.get_y(9);
    p2.show_point();
    return 0;
}

程序运行效果是一致的,只不过上面的写法比较标准,如果我们不对对象进行初始化,打印结果是什么呢?下面用一段代码进行验证

#include<iostream>
//定义点类
class Point {
public:
    void get_x(int xx) {
        x = xx;
    }
    void get_y(int yy) {
        y = yy;
    }
    void show_point() {
        cout << "x:" << x << endl;
        cout << "y:" << y << endl;
    }
private:
    int x, y;
};
int main(void)
{
    //定义两个对象
    Point p1, p2;
    p1.show_point();
    p2.show_point();
    return 0;
}

代码运行结果如下:

x:-858993460
y:-858993460
x:-858993460
y:-858993460
请按任意键继续. . .

我们看到运行结果显示的是随机值,证明在新建对象后,不对其进行任何操作,这个对象只保持原有状态。如果我们想创建对象时这个对象默认是一种状态(比如x=0y=0)或者创建对象时能指定对象的状态(x=3y=4)。该怎么办呢?这时候我们的构造函数就该登场了。


类知识的补充

int a;
int a=10;
int a=10,b=a;
···
int max(int a,int b);
{
    return (a>b?a:b);
}

类和对象的基本操作类似上面代码展示的那样,类在定义完成后,系统默认生成两个构造函数(构造函数、复制构造函数),一个析构函数,构造函数是创建对象时用来初始化对象的,复制构造函数应用场合有三种:用初始化过的对象初始化另一个对象时;将对象作为函数的参数时;函数返回值为类时被调用。用来释放资源等操作(清理战场).其实普通变量赋值操作/初始化操作/作为参数进行形实结合/作为函数返回值也涉及上述操作,只不过数据都是标准类型,这部分工作都由编译器来完成。类是我们自定义的数据结构,编译器只给出默认的构造函数/析构函数。可满足一般使用,但是涉及复杂操作或者指针应用时,系统默认功能函数不能满足要求,需要自定义这些函数。


构造函数

类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。构造函数形式:

类名(参数){
    函数体
}

当我们声明一个类时,虽然我们没有写构造函数,但是编译器在编译时会给我们的类自动增加一个默认的构造函数形式如下:

类名();

这个构造函数基本什么都不做,创建对象时,对象的初始化值仍保持类创建时的模样。
接下来我们为上面的代码写一个简单的构造函数:

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //构造函数
    Point(int xx, int yy);
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//声明类内函数
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}

//声明构造函数 无返回值可以有参数
Point::Point(int xx,int yy):x(xx),y(yy) {
 cout<<"构造函数1运行"<<endl;
}
int main(void)
{
    Point p1(3,4),p2(7,8);
    p1.show_point();
    p2.show_point();
    return 0;
}

代码运行结果如下:

构造函数1运行
构造函数1运行
x:3
y:4
x:7
y:8
请按任意键继续. . .

可以看出我们的打印结果已经和我们初始化对象时的结果一致了。
注意:
声明构造函数以后,系统默认构造函数不能使用,对象必须初始化,不进行初始化编译就会报错,当多人协作完成一个工程的时候,别人调用其他人定义的对象时,并不清楚该对象的构造函数形式是怎样的,因此为了方便我们都会为类添加上默认构造函数,这样在对对象进行初始化的时候既可以采用默认方式,也可以采用自定义的构造方式,在别人引用对象时,也不必仔细追究构造函数的形式,采用默认构造就好。添加默认构造函数很简单,只写一个空构造函数即可。下面就是具体例子:

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //构造函数1
    Point(int xx, int yy);
    //构造函数2
    Point(){
        cout<<"构造函数2运行"<<endl;
    }
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//类内函数声明 
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}

//声明构造函数 无返回值可以有参数
Point::Point(int xx,int yy):x(xx),y(yy) {
    cout<<"构造函数1运行"<<endl;
}
int main(void)
{
    Point p1(3,4);
    p1.show_point();
    p2.show_point();
    return 0;
}
构造函数1运行
构造函数2运行
x:3
y:4
x:-858993460
y:-858993460
请按任意键继续. . .

我们可以看到代码运行结果,P1点按照我们初始化的数据进行正常打印输出,p2点采用默认构造,由于类内声明xy变量均没有赋值,所以p2点打印随机数。
说明:有人会问,两个构造函数名称相同,为什么不会报错?这是因为这两个函数构成函数的重载,编译器会根据函数参数情况,自动选择功能相近的函数去执行,不会报错。
构造函数嵌套

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //声明构造函数
    Point(int xx, int yy);
    Point();
    //声明类内函数
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//声明类内函数
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}

//声明构造函数 无返回值可以有参数
Point::Point(int xx,int yy):x(xx),y(yy) {
    cout<<"构造函数1运行"<<endl;
}
//声明构造函数
Point::Point():Point(0,0){
    cout<<"构造函数2运行"<<endl;
}
int main(void)
{
    //不同的方式初始化对象
    Point p1(3,4),p2;
    p1.show_point();
    p2.show_point();
    return 0;
}

代码运行结果如下:

构造函数2运行
构造函数1运行
x:3
y:4
构造函数1运行
x:0
y:0
请按任意键继续. . .

可以看到函数的运行结果中,构造函数1被调用了两次,是因为调用构造函数2时,又调用了构造函数1,这样写的好处就是方便,构造函数形式发生改变时,只需要改动很少的量就能实现构造方案的修改。


复制构造函数

复制构造函数,也属于构造函数,其基本形式与构造函数类似,没有返回值,只不过参数是类的引用,基本样式如下:

类名(const 类名 &变量名){
    函数体
}

参数是类的引用,为什么加const呢?大家都知道引用可以双向改变数据,改变引用可改变引用对应的值,如果我们把引用传递下来的数据进行修改,会造成原数据修改,这是我们不愿意看到的,也是不合理的,加上const使引用只能单项传递数据,可以获取引用中的数据,但是并不能修改引用的数据。一般我们声明类但是没有写复制构造函数的时候,编译器自动为我们的类添加复制构造函数(主要目的是使类满足语法要求,保证成员齐全),功能是原样复制,能满足一般使用要求,但是遇上指针等系统默认的复制构造函数不能满足要求。它的应用场景很简单只有三种,哪三种呢?下面写一段伪代码进行说明

class Point;
//第一种用初始化的对象初始化另外一个变量
Point p1(3,4),p2(p1);
//第二种将对象作为参数,
void func1(Point a);
//第三种 返回值为对象的
Point func2(void);

下面写一段示例代码进行验证

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //构造函数的声明
    Point(int xx, int yy);
    Point();
    //复制构造函数的声明
    Point(const Point &p);
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//声明类内函数
void Point::get_x(int xx) {
    x = xx;
}
//声明类内函数
void Point::get_y(int yy) {
    y = yy;
}
//声明类内函数
void Point::show_point() {
    cout << "构造函数1运行" << endl;
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}
//声明构造函数
Point::Point(int xx,int yy):x(xx),y(yy) {
}
//声明构造函数
Point::Point() : Point(0,0) {
    cout << "构造函数2运行" << endl;
}
//sheng'min
Point::Point(const Point &p) {
    cout << "复制构造函数1运行" << endl;
    x = p.x;
    y = p.y;
}
//运行复制构造函数的情况的函数
void func1(Point p) {
    cout<<"作为参数"<<endl;
}
//运行复制构造函数的情况的函数
Point func2(void) {
    Point p;
    p.get_x(99);
    p.get_y(23);
    cout << "作为返回值" << endl;
    return p;
}
int main(void)
{

    Point p1(3,4),p2(p1);
    cout << "用对象初始化对象" << endl;
    func1(p1);
    func2();
    return 0;
}

代码运行结果

复制构造函数1运行
用对象初始化对象
复制构造函数1运行
作为参数
构造函数2运行
作为返回值
复制构造函数1运行
请按任意键继续. . .

我们可以看到针对所列出的三种情况,确实是调用了复制构造函数三次,由于在func2函数中默认构造了一个对象p,所以调用了一个构造函数2。


析构函数

析构函数(destructor)与构造函数相反,当对象结束其生命周期时(例如对象所在的函数已调用完毕),系统自动执行析构函数。析构函数往往用来做“清理善后” 的工作(例如在建立对象时用new开辟了一片内存空间,delete自动调用析构函数后释放内存)。
析构函数形式如下:

~类名(不能带有任何参数){
    函数体
}

这里写的例子十分简单,不涉及复杂操作,因此只展示一下用法,我们在一般类声明中,不写析构函数的话,系统同样会自动添加,只是不执行任何功能,完全只是为了满足C++语法标准,让类的成员变得齐全。
代码演示:

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //声明构造函数
    Point(int xx, int yy);
    Point();
    //复制构造函数
    Point(const Point &p);
    //析构函数
    ~Point();
    //类内函数
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//类内函数声明
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}
//构造函数声明
Point::Point(int xx,int yy):x(xx),y(yy) {
    cout << "构造函数1运行" << endl;
}
Point::Point() : Point(0,0) {
    cout << "构造函数2运行" << endl;
}
//声明复制构造函数
Point::Point(const Point &p) {
    cout << "复制构造函数1运行" << endl;
    x = p.x;
    y = p.y;
}
//声明析构函数
Point::~Point() {
    cout << "析构函数开始运行" << endl;
}
int main(void)
{
    Point p1(3,4);
    p1.show_point();
    return 0;
}

代码运行结果:

构造函数1运行
x:3
y:4
析构函数开始运行
请按任意键继续. . .

我们可以看到当函数return后,对象的生命周期结束,会调用析构函数,当然这里我们什么都没做,只是打印了一句话。


类的嵌套

我们可以在一个或者多个类的基础上,再新建一个,在新类中可以对原来的类成员进行引用二次封装等等,这里举一个简单的小例子

#include<iostream>
using namespace std;
//定义点的类
class Point {
public:
    //声明构造函数
    Point(int xx, int yy);
    Point();
    //复制构造函数
    Point(const Point &p);
    //析构函数
    ~Point();
    //类内函数
    void get_x(int xx);
    void get_y(int yy);
    void show_point();
private:
    int x, y;
};
//类内函数声明
void Point::get_x(int xx) {
    x = xx;
}
void Point::get_y(int yy) {
    y = yy;
}
void Point::show_point() {
    cout << "x:" << x << endl;
    cout << "y:" << y << endl;
}
//构造函数声明
Point::Point(int xx,int yy):x(xx),y(yy) {
    cout << "构造函数1运行" << endl;
}
Point::Point() : Point(0,0) {
    cout << "构造函数2运行" << endl;
}
//声明复制构造函数
Point::Point(const Point &p) {
    cout << "复制构造函数1运行" << endl;
    x = p.x;
    y = p.y;
}
//声明析构函数
Point::~Point() {
    cout << "析构函数开始运行" << endl;
}
//声明一个新类
class Show {
public:
    void show_point() {
        cout << "点信息为:" << endl;
        a.show_point();
    }
private:
    Point a;
};

int main(void)
{
    Show p1;
    p1.show_point();
    return 0;
}

代码运行结果:

构造函数1运行
构造函数2运行
点信息为:
x:0
y:0
析构函数开始运行
请按任意键继续. . .

猜你喜欢

转载自blog.csdn.net/z961968549/article/details/79899991