性无码一区二区三区在线观看,少妇被爽到高潮在线观看,午夜精品一区二区三区,无码中文字幕人妻在线一区二区三区,无码精品国产一区二区三区免费

Linux兵工廠(chǎng)
認(rèn)證:普通會(huì)員
所在專(zhuān)題目錄 查看專(zhuān)題
C++必知必會(huì)之基礎(chǔ)知識(shí)-常用關(guān)鍵字(1)
C++必知必會(huì)之基礎(chǔ)知識(shí)-常用關(guān)鍵字(2)
C++必知必會(huì)之基礎(chǔ)知識(shí)-常用關(guān)鍵(3)
C++基礎(chǔ)知識(shí)精髓
C++ 關(guān)鍵字constexpr
作者動(dòng)態(tài) 更多
C語(yǔ)言中宏展開(kāi)規(guī)則,你知多少?
04-22 13:41
DeepSeek對(duì)嵌入式軟件行業(yè)的分析
04-18 10:15
openssl:一個(gè)開(kāi)源的安全套接字層加密庫(kù)
04-17 09:09
記錄一次RK3399移植GDB16.2
04-16 09:21
std::thread底層實(shí)現(xiàn)原理
04-15 14:11

C++基礎(chǔ)知識(shí)精髓

大家好,我在工作經(jīng)常發(fā)現(xiàn)小伙伴們遇到一些C++的問(wèn)題都是對(duì)基礎(chǔ)知識(shí)不熟悉或理解混亂所導(dǎo)致的。正所謂萬(wàn)丈高樓平地起,作為一名合格的程序員來(lái)說(shuō),沒(méi)有良好的基本功很難達(dá)到一定的高度。而工作中大部分編程問(wèn)題都是基本功不扎實(shí)所導(dǎo)致,所以決定花些時(shí)間來(lái)整理C++相關(guān)的基本知識(shí)和基本概念供大家參考理解,每一個(gè)知識(shí)點(diǎn)都結(jié)合相關(guān)的代碼進(jìn)行驗(yàn)證。本文基本上涵蓋了C++最常用的知識(shí)點(diǎn),希望對(duì)小伙伴們有所幫助。

1. C++是一種面向?qū)ο蟮某绦蛟O(shè)計(jì)語(yǔ)言

  • C++支持?jǐn)?shù)據(jù)封裝,支持?jǐn)?shù)據(jù)封裝就是支持?jǐn)?shù)據(jù)抽象。在C++中,類(lèi)是支持?jǐn)?shù)據(jù)封裝的工具,對(duì)象則是數(shù)據(jù)封裝的實(shí)現(xiàn)。面向過(guò)程的程序設(shè)計(jì)方法與面向?qū)ο蟮某绦蛟O(shè)計(jì)方法在對(duì)待數(shù)據(jù)和函數(shù)關(guān)系上是不同的。在面向?qū)ο蟮某绦蛟O(shè)計(jì)中,將數(shù)據(jù)和對(duì)該數(shù)據(jù)進(jìn)行合法操作的函數(shù)封裝在一起作為一個(gè)類(lèi)的定義,數(shù)據(jù)將被隱藏在封裝體中,該封裝體通過(guò)操作接口與外界交換信息。對(duì)象被說(shuō)明具有一個(gè)給定類(lèi)的變量,類(lèi)類(lèi)似于C語(yǔ)言中的結(jié)構(gòu),在C語(yǔ)言中可以定義結(jié)構(gòu),但這種結(jié)構(gòu)中包含數(shù)據(jù),而不包含函數(shù)。C++中的類(lèi)是數(shù)據(jù)和函數(shù)的封裝體。在C++中,結(jié)構(gòu)可作為一種特殊的類(lèi),它雖然可以包含函數(shù),但是它沒(méi)有私有或受保護(hù)的成員。
  • C++類(lèi)中包含私有、公有受保護(hù)成員,C++類(lèi)中可定義三種不同訪(fǎng)控制權(quán)限的成員。一種是私有(Private)成員,只有在類(lèi)中說(shuō)明的函數(shù)才能訪(fǎng)問(wèn)該類(lèi)的私有成員,而在該類(lèi)外的函數(shù)不可以訪(fǎng)問(wèn)私有成員;另一種是公有(Public)成員,類(lèi)外面也可訪(fǎng)問(wèn)公有成員,成為該類(lèi)的接口;還有一種是保護(hù) (Protected)成員,這種成員只有該類(lèi)的派生類(lèi)可以訪(fǎng)問(wèn),其余的在這個(gè)類(lèi)外不能訪(fǎng)問(wèn)。

2. 命名空間

  • c++所有標(biāo)志符都在std命名空間作用域中才可見(jiàn)
   using std::cout;
   using std::endl; 或 using namepace std;
   using std::cin;
  • 命名空間中可以嵌套定義命名空間
namespace name_3
{
    namespace
    {
       int k = 200;
    };
};
  • 命名空間取別名
namespace name = name_3;

3. C++中的struct結(jié)構(gòu)體

  • 對(duì)比C語(yǔ)言中結(jié)構(gòu)體,C++中結(jié)構(gòu)體不僅可以有變量還可以有函數(shù)。

例程中聲明一個(gè)命名空間Test,Test中聲明一個(gè)結(jié)構(gòu)體Account,而Account中定義變量和聲明函數(shù)。

namespace Test
{
    struct Account
    {
        char name[30];
        double balance;
        void init(char *myname,double mybalance)
        {
            strcpy(name,myname);
            balance = mybalance;
        }
        void deposit(double amount);
        void withdraw(double amount);
        inline double getBalance()
        {
            return balance;
        }
    };
}

4. Const屬性修改

在c中const的意思是“一個(gè)不能被改變的普通變量“,在c中它總是占用存儲(chǔ)空間而且它的名字是全局符。

c++編譯器通常并不為const分配空間,它把這個(gè)定義保存在符號(hào)表中。當(dāng)const常量被使用時(shí),編譯的時(shí)候就進(jìn)行常量折疊。 c++中  編譯器不會(huì)為一般的const常量分配內(nèi)存空間, 而是將它們存放符號(hào)表中。如果取了這個(gè)常量的地址,那么編譯器將為此常量分配一個(gè)內(nèi)存空間,生成一個(gè)常量副本, 所有通過(guò)地址對(duì)常量的操作都是針對(duì)副本。 常量折疊,又叫常量替換,c++編譯器會(huì)在編譯時(shí),將const常量的字面值保存在符號(hào)表中,在編譯時(shí)使用這個(gè)字面常量進(jìn)行替換。

const_cast用法:const_cast<type_id> (expression) 該運(yùn)算符用來(lái)修改類(lèi)型的const或volatile屬性。除了const或volatile修飾之外,要求type_id和expression的類(lèi)型是一樣的。 常量指針被轉(zhuǎn)化成非常量的指針,并且仍然指向原來(lái)的對(duì)象; 常量引用被轉(zhuǎn)換成非常量的引用,并且仍然指向原來(lái)的對(duì)象;

#include <iostream>

using namespace std;

int main(int argc, const char** argv) 
{
    const int a = 10;
    const int *p = &a;

    // (*p) = 11;               // error 不可修改
    std::cout << "a:" << a << "*p:" << *p << std::endl; // a:10 *p:10

    const_cast<int&>(*p) = 11;  // 強(qiáng)制修改
    std::cout << "a:" << a << "*p:" << *p << std::endl; // a:10 *p:11

    return 0;
}

5. 引用和指針

  • 引用是一個(gè)別名,可以把它看作變量本身,但是指針本身也是一個(gè)變量
  • 引用在定義的時(shí)候必須初始化,必須綁定一個(gè)對(duì)象,如果一個(gè)對(duì)象本身不存在則取別名也沒(méi)有意義。所以對(duì)指針進(jìn)行解引用(*)的時(shí)候要對(duì)指針進(jìn)行非空檢測(cè),但是引用由于定義的時(shí)候肯定初始化了,則一定不為空。
  • 非const引用不能綁定到const對(duì)象,但是const引用可以綁定到非const對(duì)象(對(duì)象本身可以修改自己,但是不能通過(guò)引用修改對(duì)象)
  • 引用比指針安全,引用只能綁定到一個(gè)對(duì)象,指針可以指向多個(gè)地方,可能會(huì)造成內(nèi)存溢出或懸掛指針等不安全的因素
  • 形參傳引用效率高,但引用為形參最好是一個(gè)const引用,防止實(shí)參本身被修改。
#include <iostream>
using namespace std;

int main(void)
{
   int a = 10;
  // int &ref;            // error! 必須初始化
  // int &ref = 10;       // error! 
  // const int &ref = 10; // ok
   const int &ref_a = a;  // ok
  // ref_a = 11;
   a = 12;
   cout <<"ref_a: "<<a<< endl;

  /* const int b = 20;
   int &ref_b = b;       // error! 非const引用不能綁定到const變量
   const int &res_b = b; // ok


   int c = 11; 
   const int &ref_c = c; // ok
   //ref_c++;            // error!
  */

   return 0;
}

6. 內(nèi)聯(lián)函數(shù)

內(nèi)聯(lián)函數(shù):用inline關(guān)鍵字修飾的函數(shù),不加inline默認(rèn)叫外聯(lián)。

  1. 使用了inline關(guān)鍵字,編譯器并不一定把此函數(shù)當(dāng)作內(nèi)聯(lián)函數(shù)處理 內(nèi)聯(lián)函數(shù)代碼一般1-5行,并且函數(shù)體中不能出現(xiàn)循環(huán)或遞歸。
  2. 內(nèi)聯(lián)函數(shù)的聲明和定義是在一起的
  3. 在類(lèi)中聲明和定義在一起的成員函數(shù)都默認(rèn)為內(nèi)聯(lián)函數(shù)

內(nèi)聯(lián)函數(shù)和宏定義 宏定義:在預(yù)處理階段替換,但是容易產(chǎn)生二義性,不能作為類(lèi)的成員函數(shù)訪(fǎng)問(wèn)私有成員。 內(nèi)聯(lián)函數(shù):在編譯階段函數(shù)代碼替換函數(shù)名,在調(diào)用運(yùn)行的時(shí)候就沒(méi)有函數(shù)的壓棧和出棧的操作,提高運(yùn)行效率,是空間換時(shí)間。 如果要用某函數(shù)的指針調(diào)用它,則該函數(shù)不能是內(nèi)聯(lián)函數(shù),如果動(dòng)態(tài)鏈接庫(kù)中有內(nèi)聯(lián)函數(shù),那么該鏈接庫(kù)升級(jí)的時(shí)候需要重新編譯。內(nèi)聯(lián)函數(shù)和宏定義都不支持調(diào)試。

#include <iostream>
using namespace std;

#define max(a,b) (a>b?a:b)

int max1(int a,int b)
{
    return a>b?a:b;
}


inline int max2(int a,int b)
{
    return a>b?a:b;
}

int main(void)
{
    cout <<"#define: "<<max(11,12)<<endl; //預(yù)處理階段替換
    cout <<"max1: "<<max1(12,11)<<endl;   //函數(shù)的壓棧出棧
    cout <<"max2: "<<max2(12,11)<<endl;   //運(yùn)行時(shí)內(nèi)聯(lián)的展開(kāi)
    return 0;
}

7. 重載

  • 什么是函數(shù)重載: 1.函數(shù)名相同 2.參數(shù)列表必須不同(參數(shù)類(lèi)型,參數(shù)個(gè)數(shù),參數(shù)的順序不同) 3.跟函數(shù)返回值沒(méi)有關(guān)系
#include <iostream>
using namespace std;

/*
 *默認(rèn)參數(shù):如果某個(gè)參數(shù)被默認(rèn)初始化了,其右邊不能出現(xiàn)沒(méi)有被默認(rèn)初始化的參數(shù)
 * Error:
 * int average(double a=0.5, double b =1.1, double c)
 * {
 *   return (a+b+c)/2;
 * }
 */
int average(double a=0.5, double b =1.1, double c=2.1)
{
    return (a+b+c)/2;
}

int average(int a, int b)
{
    cout <<"average(int, int)" << endl;
    return (a+b)/2;
}

int average(double a, double b)
{
    cout <<"average(double, double)" << endl;
    return (a+b)/2;
}

int average(double a, double b, double c)
{
    cout <<"average(double,double,double)" << endl;
    return (a+b+c)/2;
}

int main(void)
{
    int a = 10, b = 11;
    average(a, b);
    cout <<"--------------" << endl;
    double c = 10.1, d = 10.2, e = 10.3;
    average(c, d);
    cout <<"--------------" << endl;
    average(c, d, e);
    return 0;
}

8. const成員函數(shù)和const對(duì)象

  • const成員函數(shù)(常成員函數(shù)) 不修改成員變量的函數(shù)我們一般定義為const屬性的成員函數(shù),常成員函數(shù)不能修改成員變量的值。
  • const對(duì)象 (常對(duì)象) const屬性的對(duì)象(如:const Person p),常對(duì)象所有的成員變量都是const屬性,不能用常對(duì)象調(diào)用非const的成員函數(shù)(常對(duì)象只能調(diào)用常成員函數(shù))
#include <iostream>
using namespace std;

class Person{
    public:
      Person(){}
      ~Person(){}
      void set(int var)
      {
          this->m_var = var;
      }
      int get() const //常成員函數(shù)
      {   
        //  m_var2 = 12; //error! 不修改成員變量
          return m_var;
      }
    private:
      int m_var;
      int m_var2;

};

int main(void)
{
    const Person p;   // 常對(duì)象
    //p.set(11);      // error! const對(duì)象不能修改非const成員函數(shù)
    const_cast<Person &>(p).set(11); //ok  只對(duì)當(dāng)前生效
    cout <<"const_cast: "<< p.get() <<endl;

    //p.set(12); //error! 同樣是不對(duì)的
    return 0;
}

9. static成員

  • static:靜態(tài)成員:靜態(tài)成員變量  和  靜態(tài)成員函數(shù)
  1. 靜態(tài)成員屬于整個(gè)類(lèi)不屬于某一個(gè)對(duì)象,在靜態(tài)存儲(chǔ)區(qū)分配內(nèi)存空間,被所有實(shí)例對(duì)象共享,如果是公共的(public)則可以在外部加類(lèi)作用域直接訪(fǎng)問(wèn)。
  2. 靜態(tài)成員變量只能被初始化一次,不要在頭文件中定義,為了避免重復(fù)定義。不要在構(gòu)造函數(shù)中定義(構(gòu)造函數(shù)可能被調(diào)用多次)另外是因?yàn)轭?lèi)的聲明不分配內(nèi)存空間.靜態(tài)成員變量的初始化方式:int Person::m_var = 10;靜態(tài)成員變量只在靜態(tài)存儲(chǔ)區(qū)保留一份拷貝,靜態(tài)成員變量可以聲明為本來(lái)的類(lèi)類(lèi)型
  3. 靜態(tài)成員函數(shù)沒(méi)有this指針,不能訪(fǎng)問(wèn)普通成員變量。非靜態(tài)成員函數(shù)即可以訪(fǎng)問(wèn)普通成員變量也可以訪(fǎng)問(wèn)靜態(tài)成員變量
#include <iostream>
using namespace std;

class Person{
    public:
      Person(){
         cout <<"constructor" << endl;
         m_counter++;
      }
     ~Person(){
         cout <<"distructor" << endl;
         m_counter--;
      }
    static void out_counter(){
         //cout <<m_var<< endl;  // error 不能訪(fǎng)問(wèn)普通成員變量
         cout <<"people counter: "<<m_counter << endl; //ok
     }
  
  //  private:
      int m_var;
      static int m_counter;
};

int Person::m_counter = 0;  // 靜態(tài)成員變量初始化

int  main(void)
{
    Person p1;   //constructor
    Person p2;   //constructor
    Person p3;   //constructor
 // p1.out_counter();
 // p3.out_counter();
   Person *p4 = new Person;  //constructor
   cout <<"people counter: "<<Person::m_counter << endl;  // people counter:4
   delete p4;    //distructor
   cout <<"people counter: "<<Person::m_counter << endl;  // people counter:3
   return 0;
}

10. 面向?qū)ο?/span>

  • OOP(Object Oriented Programming) 特征:封裝、繼承、多態(tài)、抽象 private和public針對(duì)類(lèi)本身和調(diào)用者 struct的缺省作用域是public class的缺省作用域是private

person.h

namespace mystd
{
class  Person
{ 
 private:
   char name[30];
   int  age;
   bool gender;
 public:
   Person(char *myname, int age, bool gender);
   ~Person();
   void show();          // 顯示基本屬性信息
   int afterYear(int n); // n年后多少歲
   inline int getAge()
   {
      return age;
   }
};
};

person.cpp

#include "person.h"
#include <iostream>
#include <string.h>
using namespace std;

namespace mystd
{
   Person::Person(char *myname, int myage, bool mygender)
   {
       strcpy(name, myname);
       age = myage;
       gender = mygender;
   }
   Person::~Person(){}
   void Person::show()         // 顯示基本屬性信息
   {
      cout <<"name: "<<name<<" age: "<<age<<" gender: "<<gender << endl;
   }
   int Person::afterYear(int n)// n年后多少歲
   {
      return age += n;
   }
};

main.cpp

#include "person.h"
#include <iostream>
using namespace std;
using namespace mystd;

int main(void)
{
   Person p1("Lin", 24, true);
   p1.show();
   cout <<"after ten years: " << p1.afterYear(10)<<endl;
   cout <<p1.age<< endl;
   return 0;
}

11. 構(gòu)造函數(shù)和析構(gòu)函數(shù)

  • 構(gòu)造函數(shù) 1.特殊的成員函數(shù),名字跟類(lèi)名相同,沒(méi)有返回類(lèi)型,必須為public,構(gòu)造函數(shù)的作用是初始化對(duì)象的屬性。 2.如果沒(méi)有顯示的定義任何構(gòu)造函數(shù),則編譯器會(huì)自動(dòng)合成一個(gè)構(gòu)造函數(shù),如果定義類(lèi)構(gòu)造函數(shù),則編譯器不再自己合成構(gòu)造函數(shù)。 3.構(gòu)造函數(shù)可以重載 4.構(gòu)造函數(shù)初始化可以使用初始化參數(shù)列表,成員變量的初始化順序跟初始化列表的順序無(wú)關(guān),是按照成員變量的聲明順序。 5.什么時(shí)候一定要用初始化列表 有const成員變量和引用成員變量的時(shí)候一定要用初始化列表初始化這兩種變量
  • 析構(gòu)函數(shù) 沒(méi)有返回值,析構(gòu)函數(shù)名稱(chēng)類(lèi)型前加~ 1.如果是棧對(duì)象 作用域結(jié)束的時(shí)候自動(dòng)調(diào)用析構(gòu)函數(shù) 2.如果是堆對(duì)象(new出來(lái)的對(duì)象),則要程序員delete的時(shí)候才調(diào)用析構(gòu)函數(shù) 3.如果是靜態(tài)對(duì)象(在靜態(tài)存儲(chǔ)區(qū)/靜態(tài)數(shù)據(jù)區(qū)中的對(duì)象)則在程序裝入內(nèi)存的時(shí)候就構(gòu)造,進(jìn)程結(jié)束的時(shí)候析析構(gòu)。
  • 淺拷貝、深拷貝 當(dāng)由一個(gè)已有的對(duì)象來(lái)構(gòu)造一個(gè)新的對(duì)象時(shí),需要調(diào)用拷貝構(gòu)造函數(shù) 淺拷貝(位拷貝):對(duì)象成員變量沒(méi)有使用動(dòng)態(tài)分配內(nèi)存空間的時(shí)候,對(duì)象和對(duì)象之間進(jìn)行拷貝構(gòu)造的時(shí)候使用淺拷貝就行 深拷貝:如果對(duì)象內(nèi)存使用了動(dòng)態(tài)分配內(nèi)存空間,則要使用深拷貝(顯示定義進(jìn)行內(nèi)存拷貝的拷貝構(gòu)造函數(shù)) 如果不進(jìn)行深拷貝,則會(huì)造成懸掛指針,多次析構(gòu)同一塊堆內(nèi)存
  • 什么時(shí)候會(huì)調(diào)用拷貝構(gòu)造函數(shù): 1.把一個(gè)對(duì)象作為參數(shù)進(jìn)行值傳遞的時(shí)候(所以說(shuō)我們一般把對(duì)象作為參數(shù)的時(shí)候傳對(duì)象的const引用) 2.把一個(gè)對(duì)象作為返回值的時(shí)候 如果存在拷貝構(gòu)造函數(shù)的需求,沒(méi)有顯示的定義拷貝構(gòu)造函數(shù),則編譯器會(huì)自動(dòng)生成一個(gè)拷貝構(gòu)造函數(shù)。如果顯示定義了拷貝構(gòu)造函數(shù)之后,則會(huì)調(diào)用該顯示定義的拷貝構(gòu)造函數(shù),但是編譯器還是會(huì)自動(dòng)生成一個(gè)拷貝構(gòu)造函數(shù)。新創(chuàng)建的對(duì)象去調(diào)用拷貝構(gòu)造函數(shù)。

constructor.cpp

#include <iostream>
using namespace std;

class Person
{
   public:
       Person(){cout <<"---constructor---"<< endl;}
      // Person(int a){m_var1 = a;}
       Person(int a):m_var1(a),m_var2(m_var2),m_var3(a)     
       {
        // m_var3 = 3; //error
         cout <<"Person(int, int) constructor" << endl; 
       }
       ~Person(){cout <<"---distructor---" << endl;} 
       void show(){cout <<"m_var1: "<<m_var1 <<" m_var2: "<<m_var2<< endl;}
   private:
     int m_var1;
     int m_var2;
     const int m_var3;
    // int &ref;
     
};

Person p1(10);

int main()
{
   // Person p(10, 30);
   // p.show();
    cout <<"----------------" << endl;
    Person *p = new Person(10);
    p->show();
    delete p;
    p1.show();
    cout <<"----------------" << endl;
    return 0;
}

copy_constructor.cpp

#include <iostream>
#include <string>
using namespace std;

class Computer{
     public:
       Computer(){}
       Computer(Computer&){
         cout <<"----computer constructor----" << endl;
       }
       ~Computer(){}
     private:
       string name;
};


class Student{
     public:
       Student(){}
       Student(string name, int age){
           cout <<"----constructor----" << endl;
           Computer com;
           m_comp = com;
           this->name = name;
           this->age = age;
       }
       //拷貝構(gòu)造函數(shù)
        Student(const Student &s){
           cout <<"----copy constructor----" << endl;
           this->name = s.name;
           this->age = s.age;
       }
       ~Student(){}
       //把一個(gè)對(duì)象作為返回值的時(shí)候會(huì)調(diào)用該對(duì)象的一個(gè)拷貝構(gòu)造函數(shù)
       Computer getComp(){
            cout <<"getComp()"<< endl;
            return m_comp;
         
       }
       Student getst(){
            return *this; //會(huì)調(diào)用該對(duì)象的拷貝構(gòu)造函數(shù)
       }
       void disp(){
           cout <<"name: "<<name<<" age: "<<age << endl;
       }
     private:
       string name;
       int    age;
       Computer m_comp;
};

//把對(duì)象作為參數(shù)進(jìn)行值傳遞的時(shí)候拷貝構(gòu)造函數(shù)會(huì)被調(diào)用
void disp_out(Student s)
{
     s.disp();
}


int main(void)
{
    Student s1("Lin", 20);
    s1.disp();
    Student s2 = s1; // 自動(dòng)調(diào)用拷貝構(gòu)造函數(shù)
    s2.disp(); 
    Student s3(s2);  // 顯式使用拷貝構(gòu)造函數(shù)
    s3.disp();
    cout <<"******************" << endl;
    disp_out(s3);    // 把一個(gè)對(duì)象作為值傳遞的時(shí)候會(huì)調(diào)用拷貝構(gòu)造函數(shù)
    cout <<"------------------" << endl;
    s1.getComp();
    s3.getst();
    return 0;
}

deep_copy.cpp

#include <iostream>
#include <string.h>
using namespace std;

class Mystring{
    public:
      Mystring(char *str, int counter){
         m_str = new char[counter+1];
         memcpy(m_str, str, counter);
         m_counter = counter;
         m_str[counter+1] = '\0';
      }
      //顯示定義拷貝構(gòu)造函數(shù) 進(jìn)行深拷貝(也就是進(jìn)行內(nèi)存的拷貝)
       Mystring(const Mystring &str){
        // m_str =  str.m_str; // error!
         cout <<"deep copy constructor" << endl;
         this->m_str = new char[str.m_counter+1];
         memcpy(m_str, str.m_str, str.m_counter);
         this->m_counter = str.m_counter;
         m_str[m_counter+1] = '\0';
      }
     ~Mystring(){
         cout <<"distructor" << endl;
         delete []m_str;
      }
      void disp(){
         cout <<hex<<m_str<< endl;
      }

    private:
     char *m_str;
     int m_counter;
};

int main(void)
{
    Mystring str("briupemsd1109", 13);
    str.disp();
    Mystring str1 = str;  //用一個(gè)已有的對(duì)象去構(gòu)造一個(gè)新的對(duì)象
    str1.disp();
    return 0;
}

12. this指針

  • 類(lèi)的任何對(duì)象的成員函數(shù)都會(huì)有一個(gè)隱含的this指針,也就是該類(lèi)對(duì)象的一個(gè)指針。如果要返回一個(gè)對(duì)象的引用則可以返回 *this表示對(duì)象本身。

address.h

#ifndef _ADDRESS_H_
#define _ADDRESS_H_
#include <string>
#include <iostream>
using namespace std;

class Address{
    public:
      Address(){}
      Address(string country, string province, string city, string street)
     {
         this->country = country;
         this->province = province;
         this->city = city;
         this->street = street;
     }
     ~Address(){}
     void setProvince(string province){
         this->province = province;
     }
     string getProvince() const{
         return province;
     }
     void setStreet(string street){
         this->street = street;
     }
     string getStreet() const{
         return street;
     }
     void out(){
         cout <<country<<"-"<<province<<"-"<<city<<"-"<<street<<endl;

     }
    private:
      string country;
      string province;
      string city;
      string street;
};
#endif

player.h

#ifndef _PLAYER_H_
#define _PLAYER_H_

#include "address.h"
#include <iostream>
using namespace std;
class Player{
   public:
      Player(){addr = NULL;}
      Player(int num, string name, int age, double salary)
      {
          this->num = num;
          this->name = name;
          this->age = age;
          this->salary = salary;
          this->addr = NULL;
      }
      Player(int num, string name, int age, double salary, Address *addr){
          this->num = num;
          this->name = name;
          this->age = age;
          this->salary = salary;
          this->addr = addr; 
      }
     ~Player(){}
     void setNum(int num){
          this->num = num;
     }
     int getNum() const{
           return num;
     }  
     void setAge(int age){
          this->age = age;
     }
     int getAge() const{
          return age;
     }
     void setSalary(double salary){
          this->salary = salary;
     }
     double getSalary() const{
          return salary;
     }
     void setAddress(Address *addr){
          this->addr = addr;
     }
     Address *getAddress(){
          return addr;
     }
     void out(){
          cout <<"num:  "<<num<< endl;
          cout <<"name: "<<name<< endl;
          cout <<"age:  " <<age<<endl;
          cout <<"salary: "<<salary <<endl;
          if(addr != NULL){
              addr->out();
          }
          cout <<"******************" << endl;
     }
   private:
      int num;
      string name;
      int age;
      double salary;
      Address *addr;
};

#endif

player_test.cpp

#include "address.h"
#include "player.h"
#include <iostream>

using namespace std;

int main(void)
{
   Address addr("china", "shanghai", "shanghai","huaihai RD");
   Player p1(17, "Lin", 24, 10000, &addr);
   p1.out();
   cout <<"-------------------" << endl;
   Player p2(24, "Kobe", 34, 20000);
   Address addr2("china", "jiangsu", "kunshan","xuey RD");
   p2.setAddress(&addr2);
   p2.out();
   cout <<"-------------------" << endl;
   Address *addr3 = new Address("USA", "MAIAMI", "MAIAMI", "MM.RD");
   Player *p3 = new Player(6, "James", 28, 20000, addr3);
   p3->out();
   delete addr3;
   delete p3;
   return 0;
} 

13. 友元

類(lèi)具備封裝和信息隱藏的特性。只有類(lèi)的成員函數(shù)才能訪(fǎng)問(wèn)類(lèi)的私有成員,程序中的其他函數(shù)是無(wú)法訪(fǎng)問(wèn)私有成員的。非成員函數(shù)能夠訪(fǎng)問(wèn)類(lèi)中的公有成員,但是假如將數(shù)據(jù)成員都定義為公有的,這又破壞了隱藏的特性。另外,應(yīng)該看到在某些情況下,特別是在對(duì)某些成員函數(shù)多次調(diào)用時(shí),由于參數(shù)傳遞,類(lèi)型檢查和安全性檢查等都需要時(shí)間開(kāi)銷(xiāo),而影響程序的運(yùn)行效率。 為了解決上述問(wèn)題,提出一種使用友元的方案。友元是一種定義在類(lèi)外部的普通函數(shù),但他需要在類(lèi)體內(nèi)進(jìn)行說(shuō)明,為了和該類(lèi)的成員函數(shù)加以區(qū)別,在說(shuō)明時(shí)前面加以關(guān)鍵字friend。友元不是成員函數(shù),但是他能夠訪(fǎng)問(wèn)類(lèi)中的私有成員。友元的作用在于提高程序的運(yùn)行效率,但是,他破壞了類(lèi)的封裝性和隱藏性,使得非成員函數(shù)能夠訪(fǎng)問(wèn)類(lèi)的私有成員。

  • 友元包括:友元函數(shù)、友元類(lèi)關(guān)鍵字:friend友元函數(shù): 友元函數(shù)的特點(diǎn)是能夠訪(fǎng)問(wèn)類(lèi)中的私有成員的非成員函數(shù)。友元函數(shù)從語(yǔ)法上看,他和普通函數(shù)相同,即在定義上和調(diào)用上和普通函數(shù)相同。友元類(lèi): 友元類(lèi)的所有成員函數(shù)都是另一個(gè)類(lèi)的友元函數(shù),都可以訪(fǎng)問(wèn)另一個(gè)類(lèi)中的隱藏信息(包括私有成員和保護(hù)成員)。 當(dāng)希望一個(gè)類(lèi)可以存取另一個(gè)類(lèi)的私有成員時(shí),可以將該類(lèi)聲明為另一類(lèi)的友元類(lèi)。定義友元類(lèi)的語(yǔ)句格式如下: friend class 類(lèi)名; 其中:friend和class是關(guān)鍵字,類(lèi)名必須是程序中的一個(gè)已定義過(guò)的類(lèi)。 例如,以下語(yǔ)句說(shuō)明類(lèi)B是類(lèi)A的友元類(lèi): class A { … public: friend class B; … }; 經(jīng)過(guò)以上說(shuō)明后,類(lèi)B的所有成員函數(shù)都是類(lèi)A的友元函數(shù),能存取類(lèi)A的私有成員和保護(hù)成員。
  • 使用友元類(lèi)時(shí)注意: (1) 友元關(guān)系不能被繼承。 (2) 友元關(guān)系是單向的,不具有交換性。若類(lèi)B是類(lèi)A的友元,類(lèi)A不一定是類(lèi)B的友元,要看在類(lèi)中是否有相應(yīng)的聲明。 (3) 友元關(guān)系不具有傳遞性。若類(lèi)B是類(lèi)A的友元,類(lèi)C是B的友元,類(lèi)C不一定是類(lèi)A的友元,同樣要看類(lèi)中是否有相應(yīng)的申明

注意事項(xiàng): 1.友元可以訪(fǎng)問(wèn)類(lèi)的私有成員。 2.只能出現(xiàn)在類(lèi)定義內(nèi)部,友元聲明可以在類(lèi)中的任何地方,一般放在類(lèi)定義的開(kāi)始或結(jié)尾。 3.友元可以是普通的非成員函數(shù),或前面定義的其他類(lèi)的成員函數(shù),或整個(gè)類(lèi)。 4.類(lèi)必須將重載函數(shù)集中每一個(gè)希望設(shè)為友元的函數(shù)都聲明為友元。 5.友元關(guān)系不能繼承,基類(lèi)的友元對(duì)派生類(lèi)的成員沒(méi)有特殊的訪(fǎng)問(wèn)權(quán)限。如果基類(lèi)被授予友元關(guān)系,則只有基類(lèi)具有特殊的訪(fǎng)問(wèn)權(quán)限。該基類(lèi)的派生類(lèi)不能訪(fǎng)問(wèn)授予友元關(guān)系的類(lèi)。

14. 繼承

繼承:類(lèi)與類(lèi)之間的關(guān)系 父類(lèi)(基類(lèi))  子類(lèi)(派生類(lèi))   繼承語(yǔ)法 構(gòu)建子類(lèi)對(duì)象,先調(diào)用父類(lèi)的構(gòu)造函數(shù),再調(diào)用子類(lèi)自己的構(gòu)造函數(shù),析構(gòu)的時(shí)候先調(diào)用子類(lèi)自己的析構(gòu)函數(shù),再調(diào)用父類(lèi)的析構(gòu)函數(shù) 父類(lèi)中的public和protected的成員變量和成員函數(shù)都會(huì)被子類(lèi)繼承下來(lái)

覆蓋: 如果子類(lèi)中有和父類(lèi)函數(shù)名相同且參數(shù)相同的成員函數(shù),則在子類(lèi)對(duì)象調(diào)用該成員函數(shù)時(shí)會(huì)把父類(lèi)的覆蓋掉

隱藏: 如果子類(lèi)中有和父類(lèi)函數(shù)名相同但參數(shù)不同的成員函數(shù), 則會(huì)在父類(lèi)中該名稱(chēng)的成員函數(shù)會(huì)被隱藏掉

父類(lèi)的指針綁定子類(lèi)的對(duì)象 OK 子類(lèi)的指針綁定父類(lèi)的對(duì)象 error!

通過(guò)對(duì)象指針進(jìn)行的普通成員函數(shù)調(diào)用,僅僅與指針的類(lèi)型有關(guān),而與此刻指針正指向什么對(duì)象無(wú)關(guān)。想要實(shí)現(xiàn)當(dāng)指針指向不同對(duì)象時(shí)執(zhí)行不同的操作就必須將基類(lèi)中相應(yīng)的成員函數(shù)定義為虛函數(shù)。

inherit.cpp

#include <stdio.h>
#include <iostream>
using namespace std;

// 派生類(lèi)是基類(lèi)的具體化,而基類(lèi)是派生類(lèi)的抽象。
// 在多繼承時(shí),如果省略繼承方式,默認(rèn)為private
// 如果在派生類(lèi)中聲明了一個(gè)與基類(lèi)成員相同名字的函數(shù),派生類(lèi)的新成員會(huì)覆蓋基類(lèi)的同名成員

/* 不管何種繼承 基類(lèi)的私有程序都不能被派生類(lèi)繼承 否則會(huì)破壞C++的封裝特性
 * 基類(lèi)的友元函數(shù)也不能被繼承,友元只是能訪(fǎng)問(wèn)指定類(lèi)的私有和保護(hù)成員的自定義函數(shù),不是被指定類(lèi)的成員,自然不能繼承
 * 基類(lèi)與派生類(lèi)的靜態(tài)成員函數(shù)與靜態(tài)成員是共用一段空間的,即靜態(tài)成員和靜態(tài)成員函數(shù)是可以繼承的
 */
// public公有繼承時(shí) 基類(lèi)的公用成員public和保護(hù)成員protected在派生類(lèi)中保持原有的訪(fǎng)問(wèn)屬性,其私有成員仍為基類(lèi)私有,即在派生類(lèi)中不能訪(fǎng)問(wèn),在類(lèi)外也不能訪(fǎng)問(wèn)
// protected保護(hù)繼承 特點(diǎn)是基類(lèi)的所有公有成員和保護(hù)成員都成為派生類(lèi)的保護(hù)成員,并且只能被它的派生類(lèi)成員函數(shù)或友元訪(fǎng)問(wèn),基類(lèi)的私有成員仍然是私有的
// private私有繼承 私有繼承即所有基類(lèi)成員均變成派生類(lèi)的私有成員,基類(lèi)的私有成員仍然不能在派生類(lèi)中訪(fǎng)問(wèn)

class BASE
{
public:
    void who()
    {
        cout << "this is base !" << endl;
    }

      void Fun()
      {
           cout << "this is base Fun ! " << endl;
      }
};

class CD1:public BASE
{
public:
    void who()
    {
        cout << "this is CD1 !" << endl;
    }
};

class CD2:public BASE
{
public:
    void who()
    {
        cout << "this is CD2 !" << endl;
    }
};


int main(int argc, char* argv[])
{
    CD1 obj1;
    CD2 obj2;

      obj1.Fun();
      obj2.Fun();

    obj1.who();  //this is CD1 !
    obj2.who();  //this is CD2 !

    return 0;
}

15. 虛函數(shù)

  • 什么是虛函數(shù) 簡(jiǎn)單地說(shuō),就是在成員函數(shù)前加關(guān)鍵字virtual,這樣這個(gè)成員函數(shù)就變成了虛函數(shù)。 虛函數(shù)允許派生類(lèi)取代基類(lèi)所提供的實(shí)現(xiàn)。編譯器確保當(dāng)對(duì)象為派生類(lèi)時(shí),派生類(lèi)的實(shí)現(xiàn)總是被調(diào)用,即使對(duì)象是使用基類(lèi)指針訪(fǎng)問(wèn)而不是派生類(lèi)的指針。

在函數(shù)形參表后面寫(xiě)上= 0以指定純虛函數(shù),含有純虛函數(shù)的對(duì)象(抽象類(lèi))不能被實(shí)例化,只能作為基類(lèi)被繼承。

virtual.cpp

#include <stdio.h>
#include <iostream>
using namespace std;


/**************************
*加virtual與不加virtual的區(qū)別
***************************/
class BASE
{
public:
    void who()  
    {
        cout << "this is base !" << endl;
    }
/*
    virtual void who()     //virtual
    {
        cout << "this is base !" << endl;
    }
*/
};

class CD1:public BASE
{
public:
    void who()
    {
        cout << "this is CD1 !" << endl;
    }
};

class CD2:public BASE
{
public:
    void who()
    {
        cout << "this is CD2 !" << endl;
    }
};

int main(int argc, char* argv[])
{
    BASE obj;
    BASE *p;
    CD1 obj1;
    CD2 obj2;

    p = &obj;
    p->who();

    p = &obj1;
    p->who();

    p = &obj2;
    p->who();

    obj1.who();
    obj2.who();

    return 0;
}

16. 模板

C++中的一個(gè)概念:泛型編程:所謂泛型編程就是獨(dú)立于任何特定類(lèi)型的方式編寫(xiě)代碼。模板是泛型編程的基礎(chǔ)。

  • 模板函數(shù): 函數(shù)模板是生成函數(shù)代碼的樣板,當(dāng)參數(shù)類(lèi)型確定后,編譯時(shí)用函數(shù)模板生成一個(gè)具有確定類(lèi)型的函數(shù),這個(gè)由函數(shù)模板而生成的函數(shù)稱(chēng)為模板函數(shù)。 模板定義以關(guān)鍵字template開(kāi)始,后接模板形參表,模板形參表是用尖括號(hào)括住的一個(gè)或多個(gè)模板形參的列表,形參之間以逗號(hào)分開(kāi)。
  • inline函數(shù)模板: 函數(shù)模板可以用與非模板函數(shù)一樣的方式聲明為inline。說(shuō)明符放在模板形參表之后、返回類(lèi)型之前,不能放在關(guān)鍵字template之前。
template <typename T> inline T min(const T&, const T&);  //ok
inline template <typename T> T min(const T&, const T&);  //error
  • 類(lèi)模板 由于篇幅有限,關(guān)注(Linux兵工廠(chǎng)),后臺(tái)回復(fù)C++獲取全部實(shí)例代碼。

17. 類(lèi)的大小與成員變量的訪(fǎng)問(wèn)

  • 類(lèi)所占字節(jié)大小似于結(jié)構(gòu)體,與成員變量有關(guān)
#include <iostream>
using namespace std;

class A{
   public:
      A():m_var1(10),m_var2('a'),m_var3('b'){}
     ~A(){}
      void disp(){
        cout <<"m_var1="<<m_var1<<" m_var2="<<m_var2<<" m_var3="<<m_var3<<endl;
      }
   private:
     int  m_var1;
     char m_var2;
     char m_var3;
};

int main(void)
{
    A a;
    a.disp();
    cout <<"m_var1: "<<*((int*)(&a))<< endl;
    cout <<"m_var2: "<<*((char*)(&a)+4)<<endl;
    cout <<"m_var3: "<<*((char*)(&a)+5)<<endl;
    cout <<sizeof(a) << endl;
    
    /*
    m_var1=10 m_var2=a m_var3=b
    m_var1: 10
    m_var2: a
    m_var3: b
    8
    */

    return 0;
}

聲明:本內(nèi)容為作者獨(dú)立觀點(diǎn),不代表電子星球立場(chǎng)。未經(jīng)允許不得轉(zhuǎn)載。授權(quán)事宜與稿件投訴,請(qǐng)聯(lián)系:editor@netbroad.com
覺(jué)得內(nèi)容不錯(cuò)的朋友,別忘了一鍵三連哦!
贊 3
收藏 4
關(guān)注 37
成為作者 賺取收益
全部留言
0/200
成為第一個(gè)和作者交流的人吧