【C++复习总结回顾】—— 【三】类与对象

需要更好的阅读的体验请移步 👉 小牛肉的个人博客 👈



一、面向对象程序设计的基本特点

二、类成员的访问控制

public

类外(main()函数)不能访问 private 和 protected 类型,只能访问声明 public 的对外接口

private

类开头若不加访问权限,则默认为private类型

  • 可被基类的成员函数访问
  • 可被基类的友元函数访问

protected

  • 可被基类的成员函数访问
  • 可被基类的友元函数访问
  • 派生类的成员函数可以访问 当前对象 基类的protected成员

举例如下:

class A{
    public: int c;
    private: int b;
    protected: int a;
};
class B: public A{
    void func(){
        c = 1; //right
        b = 1; //wrong
        a = 1; //right
        B f;
        f.a = 1 //wrong f是新构造的对象,不是func()面向的当前对象
    }
}
int main(){
    B boo;
    A aoo;
    
    aoo.b = 1 ; //worng
    aoo.a = 1; //wrong
    boo.b = 1; //wrong
    boo.a = 1; //wrong
    aoo.c = 1; //right
    boo.c = 1; //right
    return 0;
}

三、构造函数/析构函数/复制构造函数

1. 构造函数:

构造函数的作用:在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态。

class Complex{
    public:
        Complex(double r, double i = 0);
};
Complex c1; //错误,缺乏不带参数的构造函数
//若Complex(double r = 0, double i = 0);则可以执行,即缺省函数
Complex(2,1); //right

可以有多个构造函数(参数类型/个数不同),但只能有一个析构函数(可把delete语句放在析构函数中,先被构造的对象最后被析构掉)。

Test *pArray[3] = {new Test(4), new Test(1,2)};
//new Test()返回 Test* 类型,即用地址初始化指针数组;
//只生成两个对象,调用两个构造函数
//若无new,则不会调用相应的构造函数,指针不会引发对象生成

2. 析构函数:

析构函数和构造函数的调用顺序

遵循原则:先被构造的函数后被析构掉

class Demo
{
    int id;
public:
    Demo(int i)
    {
        id = i;
        cout << "id=" << id << " Constructor" << endl;
    }
    ~Demo()
    {
        cout << "id=" << id << " Destructor" << endl;
    }
};

Demo d1(1); //率先创建

void Func()
{
    static Demo d2(2);
    Demo d3(3);
    cout << "Func" << endl;
}
int main()
{
    Demo d4(4);
    d4 = 6; //6被自动转换成一个Demo的*临时对象*,同时调用构造函数和析构函数
    cout << "main" << endl;
    {
        Demo d5(5);
    } //作用域
    Func();
    cout << "main ends" << endl;
    return 0;
}

运行结果:

id=1 Constructor
id=4 Constructor
id=6 Constructor
id=6 Destructor //d4 = 6临时对象的消亡
main
id=5 Constructor
id=5 Destructor
id=2 Constructor
id=3 Constructor
Func
id=3 Destructor
main ends
id=6 Destructor //Demo d4对象的消亡
id=2 Destructor
id=1 Destructor

3. 复制构造函数:

复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已存在的对象去初始化同类型的新对象。

复制构造函数被调用的三种情况:
  • 用类的一个对象取初始化另一个对象时;

  • 函数的返回值是类的对象,函数执行完成返回调用者时;

Point g(){
	 Point a(1,2);
	 return a; 
}
int main(){
	Point b;
	b = g();
	return 0;
}

a是g( )的局部对象,离开g( )之后就消亡了,不可能再返回主函数后继续生存
所以这种情况下系统会创建一个临时无名对象,该临时对象的生存期只存在于函数调用所处的表达式中,即 b = g( )中。

执行语句 return a ,实际上是调用复制构造函数将a的值复制到临时对象中,函数g( )运行结束时对象a消亡,但临时对象会存在于表达式 b = g( ) 中,计算完这个表达式,临时对象也就自动消亡了。

  • 函数的形参是类的对象,调用函数进行形参和实参结合时;

举例如下:

class Point
{ //Point 类的定义
public:
    Point(int xx = 0, int yy = 0) //构造函数,内联
    {
        x = xx;
        y = yy;
    }
    Point(const Point &p); //复制构造函数
    void setX(int xx) { x = xx; }
    void setY(int yy) { y = yy; }
    int getX() const { return x; } //常函数(第5章)
    int getY() const { return y; } //常函数(第5章)
private:
    int x, y; //私有数据
};

//复制构造函数的实现
Point::Point(const Point &p)
{
    x = p.x;
    y = p.y;
    cout << "Calling the copy constructor " << endl;
}
//形参为Point类对象
void fun1(Point p)
{
    cout << p.getX() << endl;
}
//返回值为Point类对象
Point fun2()
{
    Point a(1, 2);
    return a;
}

int main()
{
    Point a(4, 5);
    Point b(a); //用a初始化b。
    cout << b.getX() << endl;
    fun1(b);    //对象b作为fun1的实参
    b = fun2(); //函数的返回值是类对象
    cout << b.getX() << endl;
    return 0;
}
拷贝构造函数和赋值运算符(=)有啥不同?
  • 赋值运算符作用于一个已存在的对象;
  • 拷贝构造函数会创建一个新对象。

四、类的组合

注意以下代码的构造函数和复制构造函数的调用顺序(原则:内嵌类先构造)

class Point
{ //Point类定义
public:
    Point(int xx = 0, int yy = 0)
    {
        x = xx;
        y = yy;
        cout<<"constructor of Point!"<<endl;
    }
    Point(Point &p);
    int getX() { return x; }   //用于让其他类获得私有成员的值
    int getY() { return y; }
private:
    int x, y;
};
//复制构造函数的实现
Point::Point(Point &p)
{ 
    x = p.x;
    y = p.y;
    cout << "Calling the copy constructor of Point" << endl;
}

//类的组合
class Line{ //Line类的定义
public:
    //外部接口
    Line(Point xp1, Point xp2);
    Line(Line &l);
    double getLen() { return len; }
private:          //私有数据成员
    Point p1, p2; //按照此顺序调用构造函数
    double len;
};

//组合类的构造函数
Line::Line(Point xp1, Point xp2) : p2(xp2), p1(xp1) //仍然按照p1,p2的顺序调用构造函数
{
    cout << "Calling constructor of Line" << endl;
    double x = static_cast<double>(p1.getX() - p2.getX());
    double y = static_cast<double>(p1.getY() - p2.getY());
    len = sqrt(x * x + y * y);
}
//组合类的复制构造函数
Line::Line(Line &l) : p1(l.p1), p2(l.p2)
{
    cout << "Calling the copy constructor of Line" << endl;
    len = l.len;
}
//主函数
int main()
{
    Point myp1(1, 1), myp2(4, 5);
    //建立Point类的对象
    Line line(myp1, myp2); //建立Line类的对象
    Line line2(line);      //利用复制构造函数建立一个新对象
    cout << "The length of the line is: ";
    cout << line.getLen() << endl;
    cout << "The length of the line2 is: ";
    cout << line2.getLen() << endl;
    return 0;
}

五、结构体和联合体

struct

union

例如:使用联合体保存成绩信息,并且输出。

#include <string>
#include <iostream>
using namespace std;
class ExamInfo
{
private:
    string name; //课程名称
    enum
    {
        GRADE,
        PASS,
        PERCENTAGE
    } mode; //计分方式
    union {
        char grade;  //等级制的成绩
        bool pass;   //只记是否通过课程的成绩
        int percent; //百分制的成绩
    };
public: //三种构造函数,分别用等级、是否通过和百分初始化
    ExamInfo(string name, char grade) : name(name), mode(GRADE), grade(grade) {}
    ExamInfo(string name, bool pass) : name(name), mode(PASS), pass(pass) {}
    ExamInfo(string name, int percent) : name(name), mode(PERCENTAGE), percent(percent) {}
    void show();
};

void ExamInfo::show()
{
    cout << name << ": ";
    switch (mode)
    {
    case GRADE:
        cout << grade;
        break;
    case PASS:
        cout << (pass ? "PASS" : "FAIL");
        break;
    case PERCENTAGE:
        cout << percent;
        break;
    }
    cout << endl;
}

int main()
{
    ExamInfo course1("English", 'B');
    ExamInfo course2("Calculus", true);
    ExamInfo course3("C++ Programming", 85);
    course1.show();
    course2.show();
    course3.show();
    return 0;
}

六、C++中的 . 操作符与 -> 操作符

struct Person
{
    String name;
    String born;
    double money;
};

Person A;
Person *B = new Person;

A.name = "Dr.nothing";
B->name = "Dr.something"; //B->name = (*B).name
A.money = 300.0;
(*B).money = 30;
  • 若是使用到 -> 操作符则左边的变量必须是指针变量;
  • 若是使用到 . 操作符那么左边的变量不能为指针,指针变量需要使用 * 操作符访问到该地址的内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞天小牛肉

您的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值