C++:随笔6---new\delete\虚方法\抽象方法
指針是一種專門用來存儲內(nèi)存地址的數(shù)據(jù)類型。(他存儲的不是具體的數(shù)據(jù)而是別人的地址)
常用做法是:創(chuàng)建一個變量,再把這個變量的地址賦值給一個指針,然后就可以用指針去訪問這個變量的值。
事實上在C和C++中,我們完全可以在沒有創(chuàng)建變量的情況下,為有關(guān)數(shù)據(jù)分配內(nèi)存,也就是直接創(chuàng)建一個指針,并讓她指向新分配的內(nèi)存塊。
int *pointer=new int;//int *pointer表示一個指向整型變量的指針,指針的名字叫做pointer,我們用new給他創(chuàng)建一個內(nèi)存這個內(nèi)存是什么類型呢?是int型。(整型的內(nèi)存在現(xiàn)在的編譯器一般是占用了4個字節(jié)的內(nèi)存空間,那么這樣定義的語句就是說聲明一個指針變量,這個指針變量的名字叫做pointer,它指向一個整型的地址空間,用new給他創(chuàng)建出來,new事實上就是那個malloc這個函數(shù)的一個進化版本,都是差不多的只是對他進行了進一步的封裝而已)
*pointer=110;//接著給這個指針,就是new出來的這塊內(nèi)存給他賦值,賦值為110
std::cout<<*pointer;//使用這個指針變量的值把他給打印出來
delete pointer;//最后刪除這個指針,也就是釋放了這一塊new出來的內(nèi)存。
//最后一步是非常必要和關(guān)鍵的,這是因為C和C++程序不會自動釋放內(nèi)存,程序中的每一個new操作都必須有一個與之對應(yīng)的delete操作。
創(chuàng)建對象有兩種寫法,一種就是這里的如下,一種就是使用?new。
就死記住,語法這樣寫:
類?對象?(參數(shù));//括號內(nèi)的參數(shù)會自動調(diào)用構(gòu)造函數(shù)對這個類進行初始化。
http://c.biancheng.net/view/2221.html
#include<string>
#include<iostream>class Pet
{
public:Pet(std::string theName);//構(gòu)造函數(shù)void eat();void sleep();void play();
protected:std::string name;
};
class Cat :public Pet
{
public:Cat(std::string theName);void climb();void play();//對基類play的覆蓋(在原有的基礎(chǔ)上進行覆蓋)
};
class Dog :public Pet
{
public:Dog(std::string theName);void bark();void play();//對基類play的覆蓋
};
Pet::Pet(std::string theName)
{name = theName;
}
void Pet::eat()
{std::cout<<name<<"正在吃東西"<<std::endl;
}
void Pet::sleep()
{std::cout << name << "正在睡覺" << std::endl;
}
void Pet::play()
{std::cout << name << "正在玩耍" << std::endl;
}
Cat::Cat(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Cat::climb()
{std::cout << name << "正在爬樹" << std::endl;
}
void Cat::play()
{Pet::play();std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Dog::bark()
{std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{Pet::play();std::cout << name << "正在追趕那只豬" << std::endl;
}
int main()
{//第一種方法:創(chuàng)建對象//Cat cat("加菲貓");//這個Cat類實例化一個對象cat,取名叫做“加菲貓”。//Dog dog("小灰灰");//cat.eat();//使用指針的話就要用到->操作,而不能使用結(jié)構(gòu)的.操作(點操作)。//cat.sleep();//cat.play();//先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)//cat.climb();//此種創(chuàng)建對象方式可以使用Dog子類對象dog//dog.eat();//dog.sleep();//dog.play();//先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)//dog.bark();//此種創(chuàng)建對象方式可以使用//第二種方法:指針方式創(chuàng)建對象//定義一個指針變量的形式來對它進行初始化Pet *cat = new Cat("加菲貓");//運行的時候才調(diào)用new,分配的是Cat類型的指針,給了cat,(為什么它可以用Pet來接受呢?因為Cat繼承于Pet,所以使用Pet接受是沒有問題的)Pet *dog = new Dog("小灰灰");//同上//Cat子類對象catcat->eat();//使用指針的話就要用到->操作,而不能使用結(jié)構(gòu)的.操作(點操作)。cat->sleep();cat->play();//此種方法創(chuàng)建對象:只調(diào)用基類play()函數(shù),不再調(diào)用子類的play()函數(shù)//cat->climb();//此種Pet *cat = new Cat("加菲貓");創(chuàng)建對象方式:不能調(diào)用子類的該方法(但是我們明明在Cat子類里對play方法進行了覆蓋)//Dog子類對象dogcat->eat();cat->sleep();cat->play();//此種方法創(chuàng)建對象:只調(diào)用基類play()函數(shù),不再調(diào)用子類的play()函數(shù)。((但是我們明明在Dog子類里對play方法進行了覆蓋,但實際上調(diào)用的是基類的play方法Pet::play()而不是兩個覆蓋的子類中的play()方法))//cat->bark();//此種Pet *dog = new Dog("小灰灰");創(chuàng)建對象方式:不能調(diào)用子類的該函數(shù)delete cat;delete dog;return 0;
}
該最佳點就是速度最優(yōu)內(nèi)存最節(jié)省的最佳點。
因為cat和dog都是Pet類型的指針,肯定會調(diào)用Pet類型的方法,這樣子優(yōu)化之后執(zhí)行起來的速度才是最快的。
??
虛方法的版本:(只需要在基類里邊的play()函數(shù)前邊加上virtual關(guān)鍵字)
#include<string>
#include<iostream>class Pet
{
public:Pet(std::string theName);//構(gòu)造函數(shù)void eat();void sleep();virtual void play();//前邊加上關(guān)鍵字virtual變成虛函數(shù)
protected:std::string name;
};
class Cat :public Pet
{
public:Cat(std::string theName);void climb();void play();//對基類play的覆蓋(在原有的基礎(chǔ)上進行覆蓋)
};
class Dog :public Pet
{
public:Dog(std::string theName);void bark();void play();//對基類play的覆蓋
};
Pet::Pet(std::string theName)
{name = theName;
}
void Pet::eat()
{std::cout<<name<<"正在吃東西"<<std::endl;
}
void Pet::sleep()
{std::cout << name << "正在睡覺" << std::endl;
}
void Pet::play()
{std::cout << name << "正在玩耍" << std::endl;
}
Cat::Cat(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Cat::climb()
{std::cout << name << "正在爬樹" << std::endl;
}
void Cat::play()
{Pet::play();std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Dog::bark()
{std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{Pet::play();std::cout << name << "正在追趕那只豬" << std::endl;
}
int main()
{//第一種方法:創(chuàng)建對象//Cat cat("加菲貓");//這個Cat類實例化一個對象cat,取名叫做“加菲貓”。//Dog dog("小灰灰");//cat.eat();//使用指針的話就要用到->操作,而不能使用結(jié)構(gòu)的.操作(點操作)。//cat.sleep();//cat.play();//先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)//cat.climb();//此種創(chuàng)建對象方式可以使用Dog子類對象dog//dog.eat();//dog.sleep();//dog.play();//先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)//dog.bark();//此種創(chuàng)建對象方式可以使用//第二種方法:指針方式創(chuàng)建對象//定義一個指針變量的形式來對它進行初始化Pet *cat = new Cat("加菲貓");Pet *dog = new Dog("小灰灰");//Cat *cat = new Cat("加菲貓");//Dog *dog = new Dog("小灰灰");//Cat子類對象catcat->eat();//使用指針的話就要用到->操作,而不能使用結(jié)構(gòu)的.操作(點操作)。cat->sleep();cat->play();//此種方法Pet *cat = new Cat("加菲貓");創(chuàng)建對象再加上基類虛函數(shù)的方法:先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)cat->climb();//這種Cat *cat = new Cat("加菲貓");創(chuàng)建對象方式:可以調(diào)用子類的該方法(但是我們明明在Cat子類里對play方法進行了覆蓋)//Dog子類對象dogdog->eat();dog->sleep();dog->play();//此種方法創(chuàng)建對象Pet *dog = new Dog("小灰灰");再加上基類虛函數(shù)的方法:先調(diào)用基類play()函數(shù),再調(diào)用子類的play()函數(shù)dog->bark();//這種Dog *dog = new Dog("小灰灰");創(chuàng)建對象方式:可以調(diào)用子類的該函數(shù)((但是我們明明在Dog子類里對play方法進行了覆蓋,但實際上調(diào)用的是基類的play方法Pet::play()而不是兩個覆蓋的子類中的play()方法))delete cat;delete dog;return 0;
}
Tips:
??
------抽象方法------
它實際上像一個接口(接口就類似于像C中的printf()函數(shù)輸出到桌面上,因為我們只需要根據(jù)這個函數(shù)所要求的參數(shù)提示把他寫進去他就可以實現(xiàn)輸出了,但是它內(nèi)部是如何調(diào)用顯卡等的我們不用管,所以printf可以認為是一個接口);那么什么時候要實現(xiàn)它呢?當我們的子類繼承到它的時候,然后我們需要運用到這個接口的時候,才對他進行具體的實現(xiàn)。
因為下邊會有不同的動物,玩法也不同,所以在基類里邊就不需要對這個方法進行具體的實現(xiàn)。
因為在這個類里邊他是沒有實現(xiàn)的,它是一個抽象的方法,沒有實現(xiàn)的只有在繼承的時候才來實現(xiàn)它。
class Pet
{
public:Pet(std::string theName);//構(gòu)造函數(shù)virtual void eat();//虛函數(shù)virtual void sleep();//虛函數(shù)virtual void play()=0;//定義為抽象的方法。下邊不用對它進行實現(xiàn)
protected:std::string name;
};
class Cat :public Pet
{
public:Cat(std::string theName);void climb();void play();//對基類play的覆蓋(在原有的基礎(chǔ)上進行覆蓋)
};
class Dog :public Pet
{
public:Dog(std::string theName);void bark();void play();//對基類play的覆蓋
};
Pet::Pet(std::string theName)
{name = theName;
}
void Pet::eat()
{std::cout<<name<<"正在吃東西"<<std::endl;
}
void Pet::sleep()
{std::cout << name << "正在睡覺" << std::endl;
}
//void Pet::play()
//{
// std::cout << name << "正在玩耍" << std::endl;
//}//因為它是一個抽象的方法所以這里不用給他寫實現(xiàn)的東西
Cat::Cat(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Cat::climb()
{std::cout << name << "正在爬樹" << std::endl;
}
void Cat::play()
{Pet::play();std::cout << name << "正在玩球" << std::endl;
}
Dog::Dog(std::string theName):Pet(theName)//Cat的構(gòu)造器繼承Pet的構(gòu)造器
{
}
void Dog::bark()
{std::cout << name << "正在叫" << std::endl;
}
void Dog::play()
{Pet::play();std::cout << name << "正在追趕那只豬" << std::endl;
}
//下邊主函數(shù)同上
PS總結(jié):抽象方法就是在基類里邊不用對它進行寫實現(xiàn)的方法,就是虛方法=0即可;
--------多態(tài)-------
class ClxBase
{public:ClxBase(){}virtual ~ClxBase(){}virtual void dosomething()//虛函數(shù),為了方便下邊的覆蓋調(diào)用{std::cout<<"Do something in class ClxBase"<<std::endl;}};
class ClxDerived:public ClxBase
{public:ClxDerived(){}~ClxDerived(){std::cout<<"Output from the destructor of class ClxDerived"<<std::endl}void dosomething(){std::cout<<"Do something in class ClxDerived"<<std::endl;}};
int main()
{ClxBase *pTest=new ClxDerived;//進行一個聲明和定義(這里new出來的是一個ClxDerived對象,給了pTest,)(事實上這個對象就是指向子類的)pTest->dosomething();//然后pTest指向dosomethingdelete pTest;return 0;
}
析構(gòu)器都是虛方法。
#include<string>
#include<iostream>class ClxBase
{
public:ClxBase(){}//virtual ~ClxBase()//{//}//帶virtual的析構(gòu)函數(shù),下邊輸出結(jié)構(gòu)會調(diào)用子類的析構(gòu)函數(shù)如左下圖~ClxBase(){}//不帶virtual的析構(gòu)函數(shù),下邊輸出結(jié)構(gòu)不會調(diào)用子類的析構(gòu)函數(shù)如右下圖(后邊ClxDerived子類的析構(gòu)函數(shù)根本就沒有被執(zhí)行到)virtual void dosomething()//虛函數(shù),為了方便下邊的覆蓋調(diào)用{std::cout << "Do something in class ClxBase" << std::endl;}};
class ClxDerived :public ClxBase
{
public:ClxDerived(){}~ClxDerived(){std::cout << "執(zhí)行了子類的析構(gòu)函數(shù)" << std::endl;}void dosomething(){std::cout << "Do something in class ClxDerived" << std::endl;}};
int main()
{ClxBase *pTest = new ClxDerived;//進行一個聲明和定義(這里new出來的是一個ClxDerived對象,給了pTest,)(事實上這個對象就是指向子類的)pTest->dosomething();//然后pTest指向dosomething//(如果基類的析構(gòu)不帶virtual的話,意思就是它調(diào)用了這個子類,但是沒有對這個子類進行析構(gòu),這是非常非常危險的)delete pTest;return 0;
}
結(jié)果展示:
??
//(如果基類的析構(gòu)不帶virtual的話,意思就是它調(diào)用了這個子類,但是沒有對這個子類進行析構(gòu),這是非常非常危險的)
1內(nèi)存泄漏就是內(nèi)存申請了沒有進行釋放。2虛方法的作用就是使得我們的編譯器變聰明.
如果我們根本就不必要在基類里邊對它寫實現(xiàn)我們就把他寫成抽象函數(shù)也就是純虛函數(shù)=0就行了,(為什么說基類才用寫虛函數(shù),因為虛函數(shù)所繼承的函數(shù)他自動也會變成虛函數(shù)的,所以我們只用在基類里邊寫就行了)
?
總結(jié)
以上是生活随笔為你收集整理的C++:随笔6---new\delete\虚方法\抽象方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: c++成员函数的重载、覆盖、隐藏区别
- 下一篇: C++:随笔8---命名空间