真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

C++筆記(四)類和結(jié)構(gòu)體,類的繼承,多繼承,菱形繼承-創(chuàng)新互聯(lián)

前提
  • 代碼之后交付給客戶/用戶(同事)一般是給他們*.h文件,他們?nèi)タ蠢锩嬗惺裁搭?,類里面有什么接?函數(shù)
  • 具體的接口/函數(shù)實現(xiàn)是在另外的*.cpp里面實現(xiàn)的
  • 如果在練習(xí)的時候全部寫在一個*.cpp文件,有一個Sense, main函數(shù)里面是給客戶/用戶(同事)寫的,我們提供這些接口的實現(xiàn)方法和一些限制
類和結(jié)構(gòu)體
  • stsruct也可以表示一個類,那什么時候用class,什么時候用struct
  • 有些約定俗成的默認慣例
  • struct: 很少有成員函數(shù)的時候,只放public的屬性的時候
  • 稍微復(fù)雜點的時候會去用class
  • 可以用sizeof查看內(nèi)存大小,在里面有變量有函數(shù)的時候不影響內(nèi)存大小
  • 影響內(nèi)存大小的是里面的變量
結(jié)構(gòu)體
struct struct_name {data_type member1;
   data_type member2;
   // ...
};
  • struct_name 是結(jié)構(gòu)體的名稱。
  • member1, member2 是結(jié)構(gòu)體成員,可以是任意數(shù)據(jù)類型。
  • 下面是一個簡單的結(jié)構(gòu)體例子,定義了一個名為 Student 的結(jié)構(gòu)體,包含三個成員:姓名、年齡和學(xué)號:
struct Student {string name;
   int age;
   int id;
};

結(jié)構(gòu)體變量可以通過使用結(jié)構(gòu)體類型名和點運算符來訪問結(jié)構(gòu)體成員。
例如:

Student s1;
s1.name = "John Doe";
s1.age = 21;
s1.id = 6;
  • 看一個完整的案例
// C語言的結(jié)構(gòu)體
struct Student{char* name;
    int age;
    float score;
};

void struct_demo() {// 定義一個student1
    Student s1;
    s1.name = "cqy";
    s1.age = 18;
    s1.score = 100;
    // Student 2 
    Student s2;
    s2.name = "cxk";
    s2.age = 200;
    std::cout<< "Student 1 name "<< s1.name<< " age: "<< s1.age<< std::endl;
    std::cout<< "Student 2 name "<< s2.name<< " age: "<< s2.age<< std::endl;
}
  • C++中的結(jié)構(gòu)體是一種用戶自定義的數(shù)據(jù)類型,它可以用來存儲一組具有不同數(shù)據(jù)類型的數(shù)據(jù)。結(jié)構(gòu)體可以被用來描述一個實體,如學(xué)生、聯(lián)系人等。
  • 類的使用可以使得代碼有更好的結(jié)構(gòu)和高效性
  • 后面的標(biāo)準(zhǔn)容器也是用類是實現(xiàn)的
  • 類的首字母盡量大寫
// C++ 類
class Student{public: 
    char* name;
    int age;
    float score;
};

void class_demo() {// 定義一個student1
    Student s1;
    s1.name = "cqy";
    s1.age = 18;
    s1.score = 100;
    // Student 2 
    Student s2;
    s2.name = "cxk";
    s2.age = 200;
    std::cout<< "Student 1 name "<< s1.name<< " age: "<< s1.age<< std::endl;
    std::cout<< "Student 2 name "<< s2.name<< " age: "<< s2.age<< std::endl;
}
  • 成員變量通常是私有的,外界想知道成員變量很多時候得通過接口函數(shù)來
  • public的成員函數(shù)也被叫做激活函數(shù),有更好的封裝性
  • 下面這個案例有兩個激活函數(shù),先set再get
  • 經(jīng)常我們在寫的時候,成員函數(shù)寫在class里面,具體的操作寫在外面
  • 成員函數(shù)首字母小寫
// C++ 類
class Student{public: 
    // 兩個激活函數(shù)
    int get_age() {return age_; }
    void setAge(int age) {age_ = age; }
    void say();
private: 
    int age_;
    float score_;
};

void Student::say() {std::cout<< "cqy age is: "<< age_<< std::endl;
}

void class_demo() {// 定義一個student1
    Student s1;  // 實例化一個類對象
    s1.setAge(20);
    std::cout<< "Student 1 Age: "<< s1.get_age()<< std::endl;
    s1.say();
}
Student 1 Age: 20
cqy age is: 20
  • 封裝好這個類
    class放到*.h文件
// C++ 類
class Student{public: 
    // 兩個激活函數(shù)
    int get_age() {return age_; }
    void setAge(int age) {age_ = age; }
    void say();
private: 
    int age_;
    float score_;
};
  • main.cpp文件
#include#include "class_demo.h"

void Student::say() {std::cout<< "cqy age is: "<< age_<< std::endl;
    }

int main() {// 定義一個student1
    Student s1;  // 實例化一個類對象
    s1.setAge(20);
    std::cout<< "Student 1 Age: "<< s1.get_age()<< std::endl;
    s1.say();
    return 0;
}
  • 把類包進一個namespace里面,用#ifndef, #define, #endif 這三個預(yù)處理器指令組成了一組宏定義,也叫頭文件保護符,在頭文件中使用時可以保證只被包含一次
  • 這種方式可以防止重復(fù)包含頭文件,如果頭文件已經(jīng)被包含過了,那么后面再次包含該頭文件時,就會被編譯器忽略,避免重復(fù)定義符號、重復(fù)定義函數(shù)等問題。
  • .h 文件
// #pragma once
#ifndef CLASS_FIRST_
#define CLASS_FIRST_

namespace Demo{// C++ 類
class Student{public: 
    // 兩個激活函數(shù)
    int get_age() {return age_; }
    void setAge(int age) {age_ = age; }
    void say();
private: 
    int age_;
    float score_;
};
} // namespace class_demo 

#endif
  • main.cpp
#include#include "class_demo.h"

namespace Demo{void Student::say() {std::cout<< "cqy age is: "<< age_<< std::endl;
    }
}
int main() {// 定義一個student1
    Demo::Student s1;  // 實例化一個類對象
    s1.setAge(20);
    std::cout<< "Student 1 Age: "<< s1.get_age()<< std::endl;
    s1.say();
    return 0;
}
類成員的訪問權(quán)限
  • 類默認的是private
  • public可以直接訪問
  • private 是之后實例化的對象訪問不了,上面Student s1實例化出來的s1是訪問不了私有變量和私有函數(shù)的,這些私有變量和私有函數(shù)是供給類里面使用的
  • 也可以理解為private是對實例化的對象private, 對成員函數(shù)都是可見的
  • protected 用對象訪問的時候沒有區(qū)別,繼承的時候就有區(qū)別了
類的初始化
  • 簡單的看一個C++11的案例
#includeclass Person {public:
    // constructor with two parameters
    Person(std::string name = "default", int age = 0) : name_(name), age_(age) {}
    // member variables
    std::string name_;
    int age_;
};

int main() {Person p1("asd", 10);
    Person p2; 
    std::cout<< "P1 name is: "<< p1.name_<< std::endl;
    std::cout<< "P2 name is: "<< p2.name_<< std::endl;
    return 0;
}
  • python里面有一個init構(gòu)造函數(shù),C++里面也是有的

  • 實例化的有構(gòu)造函數(shù)構(gòu)造出實例化對象

  • 如果你在類中定義了構(gòu)造函數(shù),那么編譯器不再會自動生成默認構(gòu)造函數(shù)。如果你還想使用默認構(gòu)造函數(shù),你需要自己顯式地添加一個默認構(gòu)造函數(shù)。

  • 如果你在實例化類的時候不傳遞任何參數(shù),那么如果類中沒有默認構(gòu)造函數(shù),那么將會報錯,因為編譯器無法找到可用的構(gòu)造函數(shù)。

  • 如果你在類中定義了一個默認構(gòu)造函數(shù),那么在實例化類的時候不傳遞任何參數(shù),那么將會調(diào)用你自己定義的默認構(gòu)造函數(shù)。

  • 如果你使用 C++11 以上版本,可以使用關(guān)鍵字 default 來顯式地保留默認構(gòu)造函數(shù)

  • 下面也展示了兩種初始化的方法

  • 下面為*.h文件

// #pragma once
#ifndef CLASS_FIRST_
#define CLASS_FIRST_

namespace Demo{class Student{public: 
    // 保留構(gòu)造函數(shù)
    Student() = default;
    // 構(gòu)造函數(shù)的聲明
    Student(const char* name  , int age, float score);

public: 
    // 兩個激活函數(shù)
    int get_age() {return age_; }
    void setAge(int age) {age_ = age; }
    void say();
    void setName(char* name) {name_ = name;} 
    
private: 
    // 在定義的時候給成員變量賦予默認值
    const char* name_ = nullptr;
    int age_ = 0;
    float score_ = 0;
};
} // namespace class_demo 


#endif
  • main.cpp文件
#include#include "class_demo.h"

namespace Demo{// 類的初始化 
Student::Student(const char* name, int age, float score): name_(name), age_(age),score_(score) {std::cout<< "==============start Construct==============="<< std::endl;
        // 與上面同等寫法
        // name_ = name;
        // age_ = age;
        // score_ = score;
        std::cout<< "================end Construct==============="<< std::endl;
    } 

void Student::say() {std::cout<< "cqy age is: "<< age_<< std::endl;
    }
}
int main() {// 定義一個student1
    Demo::Student s1("cqy", 20, 100);  // 實例化一個類對象, 這里調(diào)用我們定義的構(gòu)造函數(shù)
    Demo::Student s2;  // 這里調(diào)用默認構(gòu)造函數(shù)
    s1.setAge(20);
    std::cout<< "Student 1 Age: "<< s1.get_age()<< std::endl;
    s1.say();
    return 0;
}
看一個C++11的例子
  • const修飾 當(dāng)函數(shù)是 const 時,表示它不會改變對象的狀態(tài)。這是一種好的編程習(xí)慣,因為它可以防止意外修改對象的狀態(tài),并且可以讓編譯器檢查錯誤。
#includeclass Shape {public:
  // 保留默認構(gòu)造函數(shù)
  Shape() = default;
  // 自己定義一個構(gòu)造函數(shù)初始化, C++ 11語法
  Shape(int width, int height): width_(width), height_(height) {}
  //  當(dāng)函數(shù)是 const 時,表示它不會改變對象的狀態(tài)。這是一種好的編程習(xí)慣,
  // 因為它可以防止意外修改對象的狀態(tài)
  int GetWidth() const {return width_;}
  int GetHeight() const {return height_;}

  // 改變對象狀態(tài)的函數(shù)
  // 改變對象狀態(tài),就是通過函數(shù)來修改對象的成員變量的值
  void setWidth(int width) {width_ = width;}
  void setHeight(int height) {height_ = height;}
  int GetArea() const {return width_ * height_;}

private:
  // 定義初始化參數(shù),不寫的話自動給0
  int width_ = 10;
  int height_ = 5;  
};

int main() {// 初始化一個shape
    Shape shape;
    std::cout<< "默認初始化的width: "<< shape.GetWidth()<< std::endl;
    std::cout<< "默認初始化的Height: "<< shape.GetHeight()<< std::endl; 
    std::cout<< "默認初始化的Area: "<< shape.GetArea()<< std::endl; 
    return 0;
}
C++里面的this特殊指針
  • 在 C++ 中,this 是一個特殊的指針,它指向當(dāng)前對象。當(dāng)我們在類的函數(shù)中使用 this->時,它會指向調(diào)用該函數(shù)的對象。

  • 比如說,在下面的代碼中:

class Shape {public:
  Shape() = default;
  Shape(int width, int height) : width_(width), height_(height) {}
  int GetWidth() const {return width_; }
  void SetWidth(int width) {width_ = width; }
  void SetWidthThroughThis(int width) {this->width_ = width; }
  private:
  int width_;
};
  • 如果我們這樣調(diào)用 SetWidth(int width) 函數(shù):
Shape shape;
shape.SetWidth(5);
  • 這個函數(shù)就會把shape對象的 width_ 成員變量賦值為 5。

  • 而如果我們調(diào)用 SetWidthThroughThis(int width) 函數(shù),就會像這樣

shape.SetWidthThroughThis(5);
  • 這個函數(shù)同樣會把 shape 對象的 width_ 成員變量賦值為 5,不同的是它使用了 this 指針來訪問 width_ 成員變量。

使用 this->是一種好的編程習(xí)慣,它可以在代碼中清晰地表示出當(dāng)前訪問的是對象的成員變量,而不是局部變量。這樣可以避免命名沖突,提高代碼的可讀性。

另外,在某些情況下,使用 this->可以解決默認參數(shù)和局部變量之間的命名沖突。

總之,使用 this->是一種可以提高代碼可讀性和健壯性的好的編程習(xí)慣。

靜態(tài)變量,函數(shù)
  • 靜態(tài)變量和靜態(tài)函數(shù)都是類的成員,它們與類本身有關(guān),而不是與對象有關(guān)。

  • 本身跟類的互動不頻繁

  • 靜態(tài)變量是類的全局變量,它只有一個實例,不管類有多少個對象,它們共享同一個靜態(tài)變量。 通過類名::來訪問。

  • 在這個例子中,我們定義了一個靜態(tài)變量 total_shapes_ 和兩個靜態(tài)函數(shù) GetTotalShapes() 和 IncreaseTotalShapes()。

  • 靜態(tài)變量 total_shapes_ 不屬于任何一個對象,所有對象共享它。

  • 靜態(tài)函數(shù) GetTotalShapes() 返回靜態(tài)變量 total_shapes_ 的值, IncreaseTotalShapes() 函數(shù)增加 total_shapes_ 的值。

#includeclass Shape {public:
  Shape() = default;
  Shape(int width, int height) : width_(width), height_(height) {}
  int GetWidth() const {return width_; }
  void SetWidth(int width) {width_ = width; }
  // 靜態(tài)變量
  static int GetTotalShapes() {return total_shapes_; }
  // 靜態(tài)函數(shù)
  static void IncreaseTotalShapes() {total_shapes_++; }
 private:
  int width_;
  int height_;
  // 靜態(tài)變量
static int total_shapes_;
};

int Shape::total_shapes_ = 0;

int main() {Shape shape1(3, 4);
Shape shape2(5, 6);
std::cout<< "Total Shapes: "<< Shape::GetTotalShapes()<< std::endl;
Shape::IncreaseTotalShapes();
Shape::IncreaseTotalShapes();
std::cout<< "Total Shapes: "<< Shape::GetTotalShapes()<< std::endl;
return 0;
}
友元函數(shù)/類
  • 在 C++ 中,友元函數(shù)是一種特殊的函數(shù),它可以訪問類的私有成員變量和私有成員函數(shù)。這是因為類的私有成員變量和私有成員函數(shù)是只能被類的成員函數(shù)訪問的,而友元函數(shù)不屬于類的成員函數(shù)。

  • 友元函數(shù)通過在類中用關(guān)鍵字 friend 聲明來實現(xiàn)。

  • 友元類改的是class的狀態(tài),不是實例化出來的object的狀態(tài)

  • 友元類/函數(shù)使用的時都要傳入實例化的object

  • 這是一個友元函數(shù)的案例:

class MyClass {friend void MyFriendFunction(MyClass& my_class);
  private:
  int x_;
};

void MyFriendFunction(MyClass& my_class) {my_class.x_ = 5; // 訪問類的私有成員變量
}
  • 在這個例子中,MyFriendFunction 是一個友元函數(shù),它可以訪問 MyClass 類的私有成員變量 x_ 。因為在 MyClass 類中使用了 friend 關(guān)鍵字來聲明 MyFriendFunction 是友元函數(shù)。
    另外,友元函數(shù)可以是一個類的成員函數(shù),也可以是一個全局函數(shù)。

  • 需要注意的是,友元函數(shù)并不屬于類的成員函數(shù),它不能訪問類的 this 指針。

  • 完整的一個大代碼

#includeusing namespace std;

class Box {public:
  // 聲明友元函數(shù)
  friend void printWidth(Box& box);
  // 聲明友元類
  friend class BigBox;
  // 保留默認構(gòu)造函數(shù)
  Box() = default;

  // 自定義構(gòu)造函數(shù)
  Box(int width): width_(width) {}

  void setWidth(float width) {width_ = width;}
  int getWidth() {return width_;}

private:
  float width_ = 5;
};

class BigBox{public:
  // 寫一個函數(shù)更改變量
   void print(int width, Box& box) {  box.setWidth(width);
      cout<< "width of box: "<< box.width_<< endl;
   }
};

void Box_test() {Box box;
  cout<< "默認的width: "<< box.getWidth()<< endl;
  box.setWidth(6);
  cout<< "更改后的width: "<< box.getWidth()<< endl;
}

void BigBox_test() {Box box;
  BigBox bigbox;
  box.setWidth(9.0);
  bigbox.print(20, box);  // 這里就把Box的width_改了,不是改實例化出來的box
  cout<< "box width after friend class change: "<< box.getWidth()<cout<< "friend box width_ is: "<< box.width_<< endl;
}
int main() {// Box_test();
  // BigBox_test();
  Box box;
  printWidth(box);
  return 0;
}
類的繼承
  • 簡單看個案例,子類可以用父類的成員函數(shù)和成員變量,但是只能用protected 和 public
  • protected: 可以用來修飾一個類里面的成員變量和成員函數(shù),實例化的對象依然不能訪問,但是子類/派生類可以訪問
  • 用public,private,protected 來外加限定繼承關(guān)系
  • 用private,proteced 繼承只能訪問到protected的成員變量/函數(shù)
  • 下面是一個public繼承的案例
#includeclass Shape{public:
  // 保留默認構(gòu)造函數(shù)
  Shape() = default;    
  Shape(int width, int height): width_(width), height_(height) {}

// 成員函數(shù)
public:
  void setWidth(int width) {width_ = width;}
  void setHeight(int height) {height_ = height;}

// 成員變量
protected:
  int width_ = 5;
  int height_ = 5;
};

class Rectangle: public Shape {public:
  // 成員函數(shù)
  int getArea() {// 繼承的class Shape 的width_, height_
    return width_ * height_; 
  } 
};

int main() {Rectangle rect;
    // 繼承了Shape就可以用他的成員函數(shù)
    rect.setHeight(10);
    rect.setWidth(10);
    std::cout<< "Area: "<< rect.getArea()<< std::endl;
    return 0;
}
多繼承
  • 多加一個
#includeclass Shape{public:
  // 保留默認構(gòu)造函數(shù)
  Shape() = default;    
  Shape(int width, int height): width_(width), height_(height) {}

// 成員函數(shù)
public:
  void setWidth(int width) {width_ = width;}
  void setHeight(int height) {height_ = height;}

// 成員變量
protected:
  int width_ = 5;
  int height_ = 5;
};

class Cost {public: 
    auto getCost(int area) {return area * 70;}
};

class Rectangle: public Shape, public Cost {public:
  // 成員函數(shù)
  int getArea() {// 繼承的class Shape 的width_, height_
    return width_ * height_; 
  } 
};


int main() {Rectangle rect;
    // 繼承了Shape就可以用他的成員函數(shù)
    rect.setHeight(10);
    rect.setWidth(10);
    std::cout<< "Area: "<< rect.getArea()<< std::endl;
    auto area = rect.getArea(); 
    auto cost = rect.getCost(area);
    std::cout<< "Cost of rect is: "<< cost<< std::endl;
    return 0;
}
菱形繼承
  • 簡單看一個菱形繼承的案例
//     A
        //    / \ 
        //   B   C 
        //   \   /
        //     D



#includeusing namespace std;

class A{public: 
  void func() {std::cout<< "Class A"<< std::endl;
  }
protected:
int base_;
};

class B: public A{public: 

  
protected:
int b_;
};

class C: public A{public: 

  
protected:
int c_;
};

class D: public B, public C{public: 

  
protected:
int d_;
};

int main() {// 實例化b
    B b;
    b.func(); 
    // 實例化d
    D d;
    d.func(); // 不可以訪問了
    return 0;
}
  • B可以訪問,但是D不能訪問

  • 因為func() 是來自于A的,B,C都繼承自A,編譯器就不知道該從哪條線來訪問func(); 就會報錯

  • 第二種解決辦法: 指明怎么訪問的就行了把 d.func(); 改成

d.B::func();
  • 第二種解決辦法: 繼承的時候?qū)懮?virtual public, d.func();就能夠訪問了
  • 這種方法維護了一個續(xù)表,通過續(xù)表可以訪問到func()的地址,這樣避免了每次實例化單獨存一個空間。
繼承的一些特殊情況
  • 在派生類/子類里邊有一樣的變量名,訪問的時候訪問的是子類的變量
  • 嵌套變量的作用域(成員里面的成員變量會覆蓋父類里面的成員變量)
  • 想使用父類里面的成員變量,需要 父類::變量(來源于父類)
  • 先去小作用域搜索,再去大作用域搜索 sizeof(object) 查看
  • 下面案例中的height_, width_在父類和子類都有的
  • 不過一般不會有這些,這種設(shè)計是很差的,我們一般維護的成員變量也就是一份
  • 但是函數(shù)是會重載的
#includeclass Shape{public:
  // 保留默認構(gòu)造函數(shù)
  Shape() = default;    
  Shape(int width, int height): width_(width), height_(height) {}

// 成員函數(shù)
public:
  void setWidth(int width) {width_ = width;}
  void setHeight(int height) {height_ = height;}

// 成員變量
protected:
  int width_ = 5;
  int height_ = 5;
};

class Cost {public: 
    auto getCost(int area) {return area * 70;}
};

class Rectangle: public Shape, public Cost {public:
  // 成員函數(shù)
  int getArea() {// 繼承的class Shape 的width_, height_
    return width_ * height_; 
  } 

  int getShapeArea() {return Shape::height_ * Shape::width_;
  }

private:
  int width_ =100;  // 嵌套變量的作用域:
  int height_ = 700;
};


int main() {Rectangle rect;
    // 繼承了Shape就可以用他的成員函數(shù)
    rect.setHeight(10);
    rect.setWidth(10);
    std::cout<< "Area: "<< rect.getArea()<< std::endl;
    auto area = rect.getArea(); 
    auto area2 = rect.getShapeArea();
    auto cost = rect.getCost(area);
    auto cost2 = rect.getCost(area2);
    std::cout<< "Cost1 of rect is: "<< cost<< std::endl;
    std::cout<< "Cost2 of rect is: "<< cost2<< std::endl;
    std::cout<< "Cost2 of rect is: "<< sizeof(Shape)<< std::endl;
    
    
    return 0;
}
重載與重寫
  • 子類的函數(shù)會重載父類的函數(shù)
  • 理解三種 over: overwirte overload override
  • overwrite: 子類覆蓋父類的的成員變量/函數(shù)
  • overload: 函數(shù)重載: 在一個類下面有兩個相同名的函數(shù),按照返回類型來重載函數(shù),或者按照傳參需求來重載函數(shù),來匹配函數(shù)
  • 這個案例就是看下面怎么調(diào)用決定怎么返回
auto getCost(int area) {return area * 70;}
  
  void getCost() {std::cout<< "We are in getCost func in calss rect "<< std::endl;
    
  }
void getCost(int area) {std::cout<< "area is "<< area<< std::endl;}
  
  void getCost() {std::cout<< "We are in getCost func in calss rect "<< std::endl;
    
  }
  • 如果子類父類都有相同名字的函數(shù),但是參數(shù)不一樣,子類依然可以把父類的函數(shù)覆蓋掉,就會overwirte, 哪怕按照父類的格式寫一樣會出問題

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


網(wǎng)站欄目:C++筆記(四)類和結(jié)構(gòu)體,類的繼承,多繼承,菱形繼承-創(chuàng)新互聯(lián)
文章路徑:http://weahome.cn/article/dgpgpj.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部