Chapter 14 - Static Member variables and Copy Constructors
Do you know the difference between a static and a non-static member of a class?
Do you understand the difference between a copy constructor, a default constructor and other constructors?
SG:Static和非static的区别
- static和非static的member不能重名
- 引用static member的时候不需要创建类的对象 (比如说call一个static的function 的时候,我们不需要创建该类的instance)。
- static的member function没有this指针,而且该类的所有对象都可以access这个static variable。
- static函数只能调用其他static函数、变量:static member functions do not operate on instance variables
- static函数不能为virtual, const, volatile, or const volatile
- instance variable有自己的copy,但是static member variables只有一个copy of the member variable in memory。
- static的variable要在class definition外面
class Tree{
private:
static int objCount;
public:
Tree(){
objCount++; //objCount increments everytime an object is created
}
int getObjCount(){
return objCount;
}
};
int Tree::objCount = 0; //如果我们不自己initialize为0,c++也会帮我们initialize为0
- static member functions:不可以调用非static的variable。static functions和variables在类的对象被创建之前就存在了。
ClassName::staticFunctionName(paramter);
(在main中调用static fuctions,::叫scope resolution operator)
Friends of Classes
- friend是一种,不是类的member,但是可以access这个类的private数据的方程。A friend function can be a regular stand-alone function, or it can be a member of another class. (In fact, an entire calss can be declared a friend of another class. )
friend ReturnType FunctionName (paramterList)
在Budget.h中定义:(想成为谁的朋友就在谁的h中定义。)
friend void AuxiliaryOffice::addBudget(double, Budget &);
在AuxilirayOffice中:
void AuxiliaryOffice::addBudget(double b, Budget &div){
auxBudget +=b;
div.corpBudget += b; //corpBudget is from Budget class.
}
- Make an entire class a friend of another class:
每个AuxiliaryOffice的function都可以访问Budget的private members。最好不要这么做,最好只让一定要access private members的方程成为friend。
friend class AuxiliaryOffice;
SG:Copy Constructor和普通Constructor
-
Copy Constructor: a copy constructor is a special constructor that is called whenever a new obkect is created and initialized with another object’s data.
公式: ClassName(const ClassName &oldObj) { }
创建一个新对象的时候用另一个对象的数据。关于:“即使你不自己定义这个copy constructor,C++会自动提供给你。“
如果你的class没有pointer variable没有动态分配的内存,那么default constructor 也可以work(shallow copy)。但是如果有pointer variables and dynamically allocated memory,你必须自己提供copy constructor。Parameter必须是一个reference对象(最好加上const keyword,因为我们不需修改pass进来的对象)。
因为如果一个对象pass by value进入copy constructor,这个copy constructor会创建一个新的copy并且存在parameter之中。当parameter的对象被创建的时候,copy constructor会被call,然后另一个parameter对象又会被创建。一直反复下去,直到内存爆炸。Copy constructor被call的三种情况:
第一,When an object is created from another object of the same type(根据一个对象的value复制新对象)。
第二,当一个对象pass by value进入function的时候。
第三,当一个对象被return回到function的时候。
StudentTestScores(const StudentTestScores &obj) {
studentName = obj.studentName;
numTestScores = obj.numTestScores;
testScores = new double[numTestScores];
for (int i = 0; i < numTestScores; i++)
testScores[i] = obj.testScores[i];
}
................................................................
StudentTestScores oneCopy = one; //calling the copy constructor
网上找的例子:
2. 普通Constructor
…
// Constructor
StudentTestScores(string name, int numScores) {
studentName = name;
createTestScoresArray(numScores);
}
Aggregation
Aggregation occurs when a class contains an instance of another class. 比如course类中有instructor和textbook这两个类的object作为private variables。在UML中用菱形标识。
Chapter 15 - Inheritance
How to define a derived class
How accessible are the parent’s private, protected and public members to the child class
What is an abstract class and how does it relates to creating objects?
What is a pure virtual function and what does it mean to a class?
Chap 15 Highlights:
Overriding and Redefining:
Overriding:(dynamic bound)
只有virtual的函数可以被override,当我们重新define一个虚拟函数的时候,我们就在override它。
In C++, the difference between overriding and redefining base class functions is that overridden functions are dynamically bound, and redefined functions are statically bound. Only virtual functions can be overridden.
譬如这个就是Redefining:(static bound)
void setScore(double s){
rawScore = s;
GradedActivity ::setScore(rawScore * percentage);}
另外,C++的Override放在signature之后:比如base class中是virtual void functionA(int arg) const,
那么derived class中就是virtual void functionA(int arg) const override。
Destructor
When you write a class with a destructor, and that class could potentially become a base class, you should always declare the destructor virtual. This is because the compiler will perform static binding on the destructor if it is not declared virtual.
多态、pure virtual functions
-
PVF的意义:确定抽象类
C++是通过拥有Pure Virtual Function来确定这个class是不是抽象类的:
抽象类没有对象,以及PVF必须被overridden(virtual void showInfo() = 0;)
(抽象类也可以有concrete methods) -
多态:根据对象类型来决定call什么函数,the ability to take many forms。c++中,多态需要reference或者指针。
当一个对象pass by value的时候,多态是不可能的。
void displayGrade (const GradedActivity activity){
cout << activity.getScore() << " " << activity.getLetterGrade();
}
//Polymorphic behavior impossible
正确的用法应该是使用指针:
void displayGrade(const GradedActivity *activity){
cout << activity->getScore() << " " << activity->getLetterGrade();
}
- 静态绑定:在compile的时候决定call哪个函数;动态绑定:根据对象类型决定使用哪个函数。
- Virtual Fuctions:(virtual这个关键字只在declaration和prototype里面用,如果你在class外面define这个函数是不要加virtual的。)
virtual char getLetterGrade() const;
指向父类的指针
我们可以assign子类对象的地址给父类的指针。限制是这个指针只能access父类拥有的functions。
BaseClass * bc = new DerivedClass (0,0,0);
不可以直接反向推回来,除非你用static_cast < subclass *>(ptr),比如:
GradedActivity * gaPtr = new GradedActivity (100);
FinalExam * fePtr = gaPtr; //ERROR!!!
TO FIX THIS, Casting needed:
FinalExam * fePtr = static_cast<FinalExam *>(gaPtr);
override和final
virtual void functionA (int arg) const override {…body…;}
virtual void message () const final; //cannot be overriden anymore
Public, Protected, Private & OOP
class Test : Grade
//class access specification默认为pivate,即使你不写
class GradedActivity{
protected:
char letter;
double score;
void determineGrade();
public:
GradedActivity(){
letter = ' ';
score = 0.0;
}
void setScore(double s){
score = s;
determineGrade();
}
double getScore() const{
return score;
}
double getLetterGrade() const{
return letter;
}
};
//Since a curved activity is a graded activity
class CurvedActivity : public GradedActivity{
protected:
double rawScore;
double percentage;
public:
CurvedActivity() : GradedActivity(){
rawScore = 0.0;
percentage = 0.0;
}
void setScore(double s){
rawScore = s;
GradedActivity ::setScore(rawScore * percentage);
}
void setPercentage(double c){
percentage = c;
}
double getPercentage() const{
return percentage;
}
double getRawScore() const{
return rawScore;
}
};
//
Textbook: Starting out with C++