【C++】構造函數protected的說明


 總結:

protected的構造函數,和private的構造函數,類似, 都是防止外部直接實例化對象,只能通過static方法才能new出對象,其實也不一定是new,主要是棧上創建被限制了,詳見下面的例子說明

區別在於protected,可以被繼承,只能進行派生類,而private的,不能派生,所有事情都必須在當前class內部實現

通常protected這種情況,class內部沒有static方法,其目的就是為了讓類只能被繼承,不能實例化當前類,只能實例化子類。  構造,拷貝構造,復制運算符都是protected。  但是析構函數要聲明成 protected,因為如果析構函數為private,派生類就不能調用。

 

注意,對於private構造函數,這里有一個破局的方式,如果在class類內部的一個方法,eg get_instance()方法中,返回一個臨時的對象,此時是可以在棧上創建成功,也可以進行析構,但是返回棧上的臨時實例的引用或指針,本身就是有問題的。如果返回的是實例,而不是指針,就要調用拷貝構造函數,這個拷貝構造函數也是在外部調用的,如果拷貝構造函數是private的,則編譯不通過。

通常,是把這個方法聲明為static,里面的局部變量也聲明為static,這種其實就是一種單例模式,只是這種單例,對象是在static內存區,不是在堆上面

public A&  A::get_instance()

{

  A a;   //此時可以創建成功,因為是A內部的function,可以調用A的構造函數,即使是private

  return a;  // 這里return,a會進行析構,也是類內部調用,可以編譯通過。但是返回的是一個棧上的實例,調用結束后,內存已經釋放,不符合編程規范。

}

 

 

 

private, 這種情況,通常就是單例模式,不能被繼承,也不能在棧上實例化,只能在static方法中new出對象。

  而,對應的,構造函數,拷貝構造函數,復制運算符都是private的,防止其他方式產生對象

 

析構函數,則

 

protected類型的,還有一個情況需要說明,參見鏈接  https://bbs.csdn.net/topics/392913065

// C++構造函數是protect的,子類的普通函數無法訪問,但是子類的構造函數可以訪問
class Base
{
protected: // protected
    Base()
    {
    }
    Base(const Base& base)
    {
    }
    const Base& operator = (const Base&)
    {
    }

    static void SFun()
    {
    }

    void Fun()
    {
    }
};

class Son : public Base
{
public:
    void Fun()
    {
        Base *p = new Base(); // error C2248: 'Base::Base': cannot access protected member declared in class 'Base'
        Fun(); // OK
        SFun(); // OK
    }

    Son()
    {
    }
    Son(const Son & son)
    {
    }
};

 

其實本質:

本質是new 了一個新的base的實例,這個實例和當前Son的實例不是同一個,也就是son只能訪問自己內部的base類的protected方法

new出來的是另外一個base實例,跟當前實例沒有關系,是兩個相互獨立的實例,因此son實例不能訪問另外一個實例的protected方法

 

原因解釋:

https://en.cppreference.com/w/cpp/language/access

protected的構造函數只能在派生類構造函數的初始化列表上進行訪問,以對對象本身進行初始化。
其它protected成員函數在派生類中也只能基於派生類去訪問。


Protected member access
Protected members form the interface for the derived classes (which is distinct from the public interface of the class).

A protected member of a class Base can only be accessed

1) by the members and friends of Base
2) by the members and friends (until C++17) of any class derived from Base, but only when operating on an object of a type that is derived from Base (including this)

1. 被Base的成員和友元訪問。
2. 被任何派生類對象的成員和友元訪問,並且這個僅僅是在操作這個派生類對象時。顯然可以看出,只能通過派生類對象調用操作派生類對象,而不能在派生類里獨立地去調用基類的構造方法去創建Base對象。

 

https://bbs.csdn.net/topics/392913065

 

=========================  百度知道上面很好的一個回答

 https://www.cnblogs.com/this-543273659/archive/2011/08/02/2125487.html

構造函數定義為private,protected

將構造函數,析構函數聲明為私有和保護的,那么對象如何創建?
已經不能從外部調用構造函數了,但是對象必須被構造,應該如何解決,麻煩大家幫忙說明,關於構造,析構函數聲明為私有和保護時的用法???
 
提出這個問題,說明你已經對c++有所思考了。

從語法上來講,一個函數被聲明為protected或者private,那么這個函數就不能從“外部”直接被調用了。
對於protected的函數,子類的“內部”的其他函數可以調用之。
而對於private的函數,只能被本類“內部”的其他函數說調用。

語法上就是這么規定的,你肯定也知道的咯。
那么為什么有時候將構造函數或者析構函數聲明為protected的或者private的?

通常使用的場景如下:
1。如果你不想讓外面的用戶直接構造一個類(假設這個類的名字為A)的對象,而希望用戶只能構造這個類A的子類,那你就可以將類A的構造函數/析構函數聲明為protected,而將類A的子類的構造函數/析構函數聲明為public。例如:
class A
{ protected: A(){}
  public: ....
};
calss B : public A
{ public: B(){}
  ....
};

A a; // error
B b; // ok

2. 如果將構造函數/析構函數聲明為private,那只能這個類的“內部”的函數才能構造這個類的對象了。這里所說的“內部”不知道你是否能明白,下面舉個例子吧。
class A
{
private:
    A(){  }
    ~A(){ }

public:
    void Instance()//類A的內部的一個函數
    {
        A a;
    }
};
上面的代碼是能通過編譯的。上面代碼里的Instance函數就是類A的內部的一個函數。Instance函數體里就構建了一個A的對象。
但是,這個Instance函數還是不能夠被外面調用的。為什么呢?
如果要調用Instance函數,必須有一個對象被構造出來。但是構造函數被聲明為private的了。外部不能直接構造一個對象出來。
A aObj; // 編譯通不過
aObj.Instance();
但是,如果Instance是一個static靜態函數的話,就可以不需要通過一個對象,而可以直接被調用。如下:class A
{
private:
    A():data(10){ cout << "A" << endl; }
    ~A(){ cout << "~A" << endl; }

    public:
    static A& Instance()
    {
        static A a;
        return a;
    }

    void Print()
    {
        cout << data << endl;
    }

private:
    int data;
};

A& ra = A::Instance();
ra.Print();

上面的代碼其實是設計模式singleton模式的一個簡單的C++代碼實現。


還有一個情況是:通常將拷貝構造函數和operator=(賦值操作符重載)聲明成private,但是沒有實現體。
這個的目的是禁止一個類的外部用戶對這個類的對象進行復制動作。
細節請看《effective C++》里面的一個條款。具體哪個條款不記得了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM