【CPP】类和对象

1- Classes and Objects

Structures

  • A struct in C is a type consisting of a sequence of data members
  • Some functions/Statements are needed to operate the data members of an object of a struct type

【CPP】类和对象_第1张图片

不不小心操作错误,不小心越界

Classes

  • You should be very careful to manipulated the data members in a struct object
  • Can we improve struct to a better one ?
  • Yes, it is class ! We can put some member functions in it
class Student
{
  private:
    static size_t student_total; // declaration only
    //inline static size_t student_total = 0; //C++17, definition outside isn't needed
    char * name;
    int born;
    bool male; 
    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
};
Student yu;
yu.setName("Yu");

firstclass.cpp

#include 
#include 

class Student
{
  public:
    char name[4];
    int born;
    bool male; 
    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
    void setBorn(int b)
    {
        born = b;
    }
    void setGender(bool isMale)
    {
        male = isMale;
    }
    void printInfo()
    {
        std::cout << "Name: " << name << std::endl;
        std::cout << "Born in " << born << std::endl;
        std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
    }
};

int main()
{
    Student yu;
    yu.setName("Yu");
    yu.setBorn(2000);
    yu.setGender(true);
    yu.born = 2001; // it can also be manipulated directly
    yu.printInfo();
    std::cout << "It's name is " << yu.name << std::endl; 
    return 0;
}
Name: Yu
Born in 2001
Gender: Male
It's name is Yu

Access Specifiers

  • You can protect data members by access specifier private
  • Then data member can only be accessed by well designed member functions

access_attribute.cpp

#include 
#include 

class Student
{
  private:
    char name[4];
    int born;
    bool male; 
  public:
    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
    void setBorn(int b)
    {
        born = b;
    }
    void setGender(bool isMale)
    {
        male = isMale;
    }
    void printInfo()
    {
        std::cout << "Name: " << name << std::endl;
        std::cout << "Born in " << born << std::endl;
        std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
    }
};

int main()
{
    Student yu;
    yu.setName("Yu");
    yu.setBorn(2000);
    yu.setGender(true);
    yu.born = 2001; // you cannot access a private member
    yu.printInfo();
    return 0;
}
access-attribute.cpp:37:8: error: 'born' is a private member of 'Student'
    yu.born = 2001; // you cannot access a private member
       ^
access-attribute.cpp:8:9: note: declared private here
    int born;
        ^

Member Functions

  • A member function can be defined inside or outside class
  • 如果在类内部实现函数则就是inline 函数

function.cpp

#include 
#include 

class Student
{
  private:
    char name[4];
    int born;
    bool male; 
  public:
    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
    void setBorn(int b)
    {
        born = b;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    Student yu;
    yu.setName("Yu");
    yu.setBorn(2000);
    yu.setGender(true);
    yu.printInfo();
    return 0;
}
Name: Yu
Born in 2000
Gender: Male

File Structures

  • The source code can be placed into multiple files

student.hpp

#pragma once

#include 
class Student
{
  private:
    char name[4];
    int born;
    bool male; 
  public:
    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
    void setBorn(int b)
    {
        born = b;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

student.cpp

#include 
#include "student.hpp"

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

如果include <> 从编译器路径查找,如果是include "" 从编译器和当前目录找

main.cpp

#include "student.hpp"

int main()
{
    Student yu;
    yu.setName("Yu");
    yu.setBorn(2000);
    yu.setGender(true);
    yu.printInfo();
    return 0;
}

CMakeList.txt

cmake_minimum_required(VERSION 3.12)

project(persondemo)

ADD_EXECUTABLE(persondemo main.cpp student.cpp)


cd multi-files
mkdir build
cd build
cmake ..
make
./persondemo
Name: Yu
Born in 2000
Gender: Male

2-Constructors and Destructors

Constructors

  • Different from struct in C, a constructor will be invoked when creating an object of a class

(1) struct in C: allocate memory
(2) class in C++: allocate memory & invoke a constructor

  • But, No constructor is defined explicitly in previous examples

(1) the compiler wil generate one with empty body

如果没有人为定义构造函数,则自动会有一个空的构造函数

  • The same name with the class
  • Have no return value

class Student
{
  private:
    char name[4];
    int born;
    bool male; 
  public:
    Student()
    {
        name[0] = 0;
        born = 0;
        male = false;
        cout << "Constructor: Person()" << endl;
    }
    }
    Student(const char * initName, int initBorn, bool isMale)
    {
        setName(initName);
        born = initBorn;
        male = isMale;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }
}
  • The members can also be initialized as follows
    Student(const char * initName): born(0), male(true)
    {
        setName(initName);
        cout << "Constructor: Person(const char*)" << endl;
    }

把成员变量born 初始化为0 , 把male 初始化为true

constructor.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    char name[4];
    int born;
    bool male; 
  public:
    Student()
    {
        name[0] = 0;
        born = 0;
        male = false;
        cout << "Constructor: Person()" << endl;
    }
    Student(const char * initName): born(0), male(true)
    {
        setName(initName);
        cout << "Constructor: Person(const char*)" << endl;
    }
    Student(const char * initName, int initBorn, bool isMale)
    {
        setName(initName);
        born = initBorn;
        male = isMale;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }

    void setName(const char * s)
    {
        strncpy(name, s, sizeof(name));
    }
    void setBorn(int b)
    {
        born = b;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    Student yu;
    yu.printInfo();

    yu.setName("Yu");
    yu.setBorn(2000);
    yu.setGender(true);
    yu.printInfo();

    Student li("li");
    li.printInfo();

    Student xue = Student("XueQikun", 1962, true);
    //a question: what will happen since "XueQikun" has 4+ characters?
    xue.printInfo();

    Student * zhou =  new Student("Zhou", 1991, false);
    zhou->printInfo();
    delete zhou;

    return 0;
}
Constructor: Person()
Name: 
Born in 0
Gender: Female
Name: Yu
Born in 2000
Gender: Male
Constructor: Person(const char*)
Name: li
Born in 0
Gender: Male
Constructor: Person(const char, int , bool)
Name: XueQ�
Born in 1962
Gender: Male
Constructor: Person(const char, int , bool)
Name: Zhou�
Born in 1991
Gender: Female

Destructors

  • The destructor will be invoked when the object is destroyed
  • Be formed from the class name preceded by a tilde(~)
  • Have no return value, no parameters
    ~Student()
    {
        cout << "To destroy object: " << name << endl;
        delete [] name;
    }

析构函数只能有一个
析构函数常做的事情:释放内存,关闭文件,断掉网络etc

destructor.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    char * name;
    int born;
    bool male; 
  public:
    Student()
    {
        name = new char[1024]{0};
        born = 0;
        male = false;
        cout << "Constructor: Person()" << endl;
    }
    Student(const char * initName, int initBorn, bool isMale)
    {
        name =  new char[1024];
        setName(initName);
        born = initBorn;
        male = isMale;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }
    ~Student()
    {
        cout << "To destroy object: " << name << endl;
        delete [] name;
    }

    void setName(const char * s)
    {
        strncpy(name, s, 1024);
    }
    void setBorn(int b)
    {
        born = b;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    {
        Student yu;
        yu.printInfo();

        yu.setName("Yu");
        yu.setBorn(2000);
        yu.setGender(true);
        yu.printInfo();
    }
    Student xue = Student("XueQikun", 1962, true);
    xue.printInfo();

    Student * zhou =  new Student("Zhou", 1991, false);
    zhou->printInfo();
    delete zhou;

    return 0;
}
g++ destructor.cpp --std=c++11
Constructor: Person()
Name: 
Born in 0
Gender: Female
Name: Yu
Born in 2000
Gender: Male
To destroy object: Yu
Constructor: Person(const char, int , bool)
Name: XueQikun
Born in 1962
Gender: Male
Constructor: Person(const char, int , bool)
Name: Zhou
Born in 1991
Gender: Female
To destroy object: Zhou
To destroy object: XueQikun

人工手动调用析构函数 delete zhou,作用域结束跳出也会自动调用析构函数
如果对于new 的对象不进行手动删除delete 则作用域结束也不会动态调用析构函数,造成内存泄漏

    Student * class1 = new Student[3]{
        {"Tom", 2000, true},
        {"Bob", 2001, true},
        {"Amy", 2002, false},
    };
  • What is the different between the following two lines?
delete class1;
delete [] class1;

array.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    char * name;
    int born;
    bool male; 
  public:
    Student()
    {
        name = new char[1024]{0};
        born = 0;
        male = false;
        cout << "Constructor: Person()" << endl;
    }
    Student(const char * initName, int initBorn, bool isMale)
    {
        name =  new char[1024];
        setName(initName);
        born = initBorn;
        male = isMale;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }
    ~Student()
    {
        cout << "To destroy object: " << name << endl;
        delete [] name;
    }

    void setName(const char * s)
    {
        strncpy(name, s, 1024);
    }
    void setBorn(int b)
    {
        born = b;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    Student * class1 = new Student[3]{
        {"Tom", 2000, true},
        {"Bob", 2001, true},
        {"Amy", 2002, false},
    };

    class1[1].printInfo();
    delete class1;
    delete []class1;


    return 0;
}
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Tom

数组调用析构函数delete class1 , 只会调用第一个对象的析构函数,后面的对象不会被调用

数组调用析构函数 delete [] class1,则会调用全部对象的析构函数

Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy
To destroy object: Bob
To destroy object: Tom

3-this pointer

Why is this needed

  • How does a member function know which name?

【CPP】类和对象_第2张图片

this Pointer

  • All methods in a function have a this pointer
  • It is set to the address of the object that invokes the method

【CPP】类和对象_第3张图片

this.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    char * name;
    int born;
    bool male; 
  public:
    Student()
    {
        name = new char[1024]{0};
        born = 0;
        male = false;
        cout << "Constructor: Person()" << endl;
    }
    Student(const char * name, int born, bool male)
    {
        this->name =  new char[1024];
        this->setName(name);
        this->born = born;
        this->male = male;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }
    ~Student()
    {
        cout << "To destroy object: " << name << endl;
        delete [] name;
    }

    void setName(const char * name)
    {
        strncpy(this->name, name, 1024);
    }
    void setBorn(int born)
    {
        this->born = born;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    Student * class1 = new Student[3]{
        {"Tom", 2000, true},
        {"Bob", 2001, true},
        {"Amy", 2002, false},
    };

    class1[1].printInfo();
    delete []class1;


    return 0;
}
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Constructor: Person(const char, int , bool)
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy
To destroy object: Bob
To destroy object: Tom

4- const and static Members

const Variables

  • statements for constants

【CPP】类和对象_第4张图片

C++不推荐用 宏

const Members

  • const member variables behavior similar with normal const variables
  • const member functions promise not to modify member variables
class Student
{
  private:
    const int BMI = 24;
  public:
    Student()
    {
        BMI = 25;//can it be modified?
    int getBorn() const
    {
        born++; //Can it be modified?
        return born;
    }
};

常量函数,const 放在后面,不然跟前面的const int相冲突。不可以修改成员变量,born 是不可以被修改的,保证不修改函数里的变量

const.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    const int BMI = 24;
    char * name;
    int born;
    bool male; 
  public:
    Student()
    {
        name = new char[1024]{0};
        born = 0;
        male = false;
        // BMI = 25;//can it be modified?
        cout << "Constructor: Person()" << endl;
    }
    Student(const char * name, int born, bool male)
    {
        this->name =  new char[1024];
        setName(name);
        this->born = born;
        this->male = male;
        cout << "Constructor: Person(const char, int , bool)" << endl;
    }
    ~Student()
    {
        cout << "To destroy object: " << name << endl;
        delete [] name;
    }

    void setName(const char * name)
    {
        strncpy(this->name, name, 1024);
    }
    void setBorn(int born)
    {
        this->born = born;
    }
    int getBorn() const
    {
        //born++; //Can it be modified?
        return born;
    }
    // the declarations, the definitions are out of the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

int main()
{
    Student yu("Yu", 2000, true);
    cout << "yu.getBorn() = " << yu.getBorn() << endl;
    return 0;
}
Constructor: Person(const char, int , bool)
yu.getBorn() = 2000
To destroy object: Yu

static members

  • static members are not bound to class instances
class Student
{
  private:
    static size_t student_total; // declaration only
  public:
    Student()
    {
        student_total++;
    }

    ~Student()
    {
        student_total--;
    }
    static size_t getTotal() {return student_total;}
};

// definition it here
size_t Student::student_total = 0; 



静态成员不绑定在类对象上,只有一个

static.cpp

#include 
#include 

using namespace std;

class Student
{
  private:
    static size_t student_total; // declaration only
    //inline static size_t student_total = 0; //C++17, definition outside isn't needed
    char * name;
    int born;
    bool male; 
  public:
    Student()
    {
        student_total++;
        name = new char[1024]{0};
        born = 0;
        male = false;
        cout << "Constructor: Person(): student_total = " << student_total << endl;
    }
    Student(const char * initName, int initBorn, bool isMale)
    {
        student_total++;
        name =  new char[1024];
        setName(initName);
        born = initBorn;
        male = isMale;
        cout << "Constructor: Person(const char, int , bool): student_total = " << student_total << endl;
    }
    ~Student()
    {
        student_total--;
        cout << "To destroy object: " << name ;
        cout << ". Then " << student_total << " students are left" << endl;
        delete [] name;
    }

    void setName(const char * s)
    {
        strncpy(name, s, 1024);
    }
    void setBorn(int b)
    {
        born = b;
    }
    static size_t getTotal() {return student_total;}
    // the declarations, the definitions are out sof the class
    void setGender(bool isMale);
    void printInfo();
};

void Student::setGender(bool isMale)
{
    male = isMale;
}
void Student::printInfo()
{
    std::cout << "Name: " << name << std::endl;
    std::cout << "Born in " << born << std::endl;
    std::cout << "Gender: " << (male ? "Male" : "Female") << std::endl;
}

size_t Student::student_total = 0; // definition it here

int main()
{
    cout << "---We have " << Student::getTotal() << " students---" << endl;

    Student * class1 = new Student[3]{
        {"Tom", 2000, true},
        {"Bob", 2001, true},
        {"Amy", 2002, false},
    };

    cout << "---We have " << Student::getTotal() << " students---" << endl;

    Student yu("Yu", 2000, true);

    cout << "---We have " << Student::getTotal() << " students---" << endl;

    class1[1].printInfo();
    delete []class1;

    cout << "---We have " << Student::getTotal() << " students---" << endl;

    return 0;
}
---We have 0 students---
Constructor: Person(const char, int , bool): student_total = 1
Constructor: Person(const char, int , bool): student_total = 2
Constructor: Person(const char, int , bool): student_total = 3
---We have 3 students---
Constructor: Person(const char, int , bool): student_total = 4
---We have 4 students---
Name: Bob
Born in 2001
Gender: Male
To destroy object: Amy. Then 3 students are left
To destroy object: Bob. Then 2 students are left
To destroy object: Tom. Then 1 students are left
---We have 1 students---
To destroy object: Yu. Then 0 students are left

静态函数里面不可以修改非静态数据

你可能感兴趣的:(CPP,c++)